<!DOCTYPE html>



  


<html class="theme-next mist use-motion" lang="zh-Hans">
<head>
  <meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
<meta name="theme-color" content="#222">









<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />
















  
  
  <link href="/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css" />







<link href="/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css" />

<link href="/css/main.css?v=5.1.4" rel="stylesheet" type="text/css" />


  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png?v=5.1.4">


  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png?v=5.1.4">


  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png?v=5.1.4">


  <link rel="mask-icon" href="/images/logo.svg?v=5.1.4" color="#222">





  <meta name="keywords" content="Hexo, NexT" />










<meta property="og:type" content="website">
<meta property="og:title" content="kyssion-blog">
<meta property="og:url" content="http://yoursite.com/page/11/index.html">
<meta property="og:site_name" content="kyssion-blog">
<meta property="og:locale" content="zh-Hans">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="kyssion-blog">



<script type="text/javascript" id="hexo.configurations">
  var NexT = window.NexT || {};
  var CONFIG = {
    root: '/',
    scheme: 'Mist',
    version: '5.1.4',
    sidebar: {"position":"left","display":"post","offset":12,"b2t":false,"scrollpercent":false,"onmobile":false},
    fancybox: true,
    tabs: true,
    motion: {"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},
    duoshuo: {
      userId: '0',
      author: '博主'
    },
    algolia: {
      applicationID: '',
      apiKey: '',
      indexName: '',
      hits: {"per_page":10},
      labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
    }
  };
</script>



  <link rel="canonical" href="http://yoursite.com/page/11/"/>





  <title>kyssion-blog</title>
  








</head>

<body itemscope itemtype="http://schema.org/WebPage" lang="zh-Hans">

  
  
    
  

  <div class="container sidebar-position-left 
  page-home">
    <div class="headband"></div>

    <header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-wrapper">
  <div class="site-meta ">
    

    <div class="custom-logo-site-title">
      <a href="/"  class="brand" rel="start">
        <span class="logo-line-before"><i></i></span>
        <span class="site-title">kyssion-blog</span>
        <span class="logo-line-after"><i></i></span>
      </a>
    </div>
      
        <p class="site-subtitle"></p>
      
  </div>

  <div class="site-nav-toggle">
    <button>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
    </button>
  </div>
</div>

<nav class="site-nav">
  

  
    <ul id="menu" class="menu">
      
        
        <li class="menu-item menu-item-home">
          <a href="/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-home"></i> <br />
            
            首页
          </a>
        </li>
      
        
        <li class="menu-item menu-item-about">
          <a href="/about/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-user"></i> <br />
            
            关于
          </a>
        </li>
      
        
        <li class="menu-item menu-item-tags">
          <a href="/tags/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-tags"></i> <br />
            
            标签
          </a>
        </li>
      
        
        <li class="menu-item menu-item-categories">
          <a href="/categories/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-th"></i> <br />
            
            分类
          </a>
        </li>
      
        
        <li class="menu-item menu-item-archives">
          <a href="/archives/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-archive"></i> <br />
            
            归档
          </a>
        </li>
      
        
        <li class="menu-item menu-item-schedule">
          <a href="/schedule/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-calendar"></i> <br />
            
            日程表
          </a>
        </li>
      
        
        <li class="menu-item menu-item-sitemap">
          <a href="/sitemap.xml" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-sitemap"></i> <br />
            
            站点地图
          </a>
        </li>
      
        
        <li class="menu-item menu-item-commonweal">
          <a href="/404/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-heartbeat"></i> <br />
            
            公益404
          </a>
        </li>
      

      
    </ul>
  

  
</nav>



 </div>
    </header>

    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          <div id="content" class="content">
            
  <section id="posts" class="posts-expand">
    
      

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/2018/10/09/dubbo深入（一）基本使用初探/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="kyssion">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="kyssion-blog">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
                
                <a class="post-title-link" href="/2018/10/09/dubbo深入（一）基本使用初探/" itemprop="url">未命名</a></h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2018-10-09T15:22:37+08:00">
                2018-10-09
              </time>
            

            

            
          </span>

          

          
            
          

          
          

          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <h2 id="深入dubbo（一）基本使用初探"><a href="#深入dubbo（一）基本使用初探" class="headerlink" title="深入dubbo（一）基本使用初探"></a>深入dubbo（一）基本使用初探</h2><h3 id="互联网架构升级过程图"><a href="#互联网架构升级过程图" class="headerlink" title="互联网架构升级过程图"></a>互联网架构升级过程图</h3><p><img src="blogimg/dubbo/1.jpg" alt=""></p>
<p>单一应用架构(单机部署所有的应用)——&gt;垂直应用架构(将单机的应用部署到相关的各种分开的服务器上，各个服务器相互独立)——&gt;分布式服务架构(在之前的各个部分出现了交互的过程)——&gt;流动计算架构soa(当系统变得复杂，各种交互混乱，玉树出现了基于中央调度的整合配置机制)——&gt;微服务</p>
<h3 id="dubbo的作用"><a href="#dubbo的作用" class="headerlink" title="dubbo的作用"></a>dubbo的作用</h3><ul>
<li>作为服务注册中心，动态的注册和发现服务，使服务的位置透明并通过在消费方获取服务提供方地址列表，实现软负载均衡和 Failover（失效备份），降低对 F5 硬件负载均衡器的依赖</li>
<li>自动画出应用间的依赖关系图，以帮助架构师理清理关系。</li>
<li>将服务现在每天的调用量，响应时间，都统计出来，作为容量规划的参考指标，可以动态调整权重，在线上，将某台机器的权重一直加大，并在加大的过程中记录响应时间的变化，直到响应时间到达阀值，记录此时的访问量，再以此访问量乘以机器数反推总容量</li>
</ul>
<h3 id="dubbo的基本架构"><a href="#dubbo的基本架构" class="headerlink" title="dubbo的基本架构"></a>dubbo的基本架构</h3><p><img src="blogimg/dubbo/2.jpg" alt=""></p>
<table>
<thead>
<tr>
<th>节点</th>
<th>角色说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>Provider</td>
<td>暴露服务的服务提供方</td>
</tr>
<tr>
<td>Consumer</td>
<td>调用远程服务的服务消费方</td>
</tr>
<tr>
<td>Registry</td>
<td>服务注册与发现的注册中心</td>
</tr>
<tr>
<td>Monitor</td>
<td>统计服务的调用次调和调用时间的监控中心</td>
</tr>
<tr>
<td>Container</td>
<td>服务运行容器</td>
</tr>
</tbody>
</table>
<h3 id="基本使用方法"><a href="#基本使用方法" class="headerlink" title="基本使用方法"></a>基本使用方法</h3><p>引申，其实dubbo并没有那么难，首先他需要的一组公共的接口，作为对外面提供的服务的入口，dubbo框架处理了寻找服务提供者等过程，使用者可以就像使用spring框架那样进行dubbo的使用，见下面的例子</p>
<ol>
<li>公共的接口</li>
</ol>
<p>注意：这个公共的接口一定要有包名，否则dubbo内部的反射处理方法将会报空值错误</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> service;</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">DemoService</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">say</span><span class="params">()</span></span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>提供maven贡其他组件使用</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span><br><span class="line"><span class="tag">&lt;<span class="name">project</span> <span class="attr">xmlns</span>=<span class="string">"http://maven.apache.org/POM/4.0.0"</span></span></span><br><span class="line"><span class="tag">         <span class="attr">xmlns:xsi</span>=<span class="string">"http://www.w3.org/2001/XMLSchema-instance"</span></span></span><br><span class="line"><span class="tag">         <span class="attr">xsi:schemaLocation</span>=<span class="string">"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">parent</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>demo<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.fen<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">version</span>&gt;</span>1.0-SNAPSHOT<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">parent</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">modelVersion</span>&gt;</span>4.0.0<span class="tag">&lt;/<span class="name">modelVersion</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>demoAPI<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">project</span>&gt;</span></span><br></pre></td></tr></table></figure>
<ol start="2">
<li>provider服务提供者</li>
</ol>
<p>xml配置文件，注意对外提供的服务一定要是接口</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span><br><span class="line"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">xmlns:xsi</span>=<span class="string">"http://www.w3.org/2001/XMLSchema-instance"</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xmlns:dubbo</span>=<span class="string">"http://code.alibabatech.com/schema/dubbo"</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xmlns</span>=<span class="string">"http://www.springframework.org/schema/beans"</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xsi:schemaLocation</span>=<span class="string">"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd</span></span></span><br><span class="line"><span class="tag"><span class="string">	http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dubbo:application</span> <span class="attr">name</span>=<span class="string">"provider"</span>&gt;</span><span class="tag">&lt;/<span class="name">dubbo:application</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dubbo:registry</span> <span class="attr">address</span>=<span class="string">"multicast://224.5.6.10:1253"</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dubbo:protocol</span> <span class="attr">name</span>=<span class="string">"dubbo"</span> <span class="attr">port</span>=<span class="string">"20880"</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"myfirstdemo"</span> <span class="attr">class</span>=<span class="string">"DemoSayImp"</span>&gt;</span><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dubbo:service</span> <span class="attr">interface</span>=<span class="string">"service.DemoService"</span> <span class="attr">ref</span>=<span class="string">"myfirstdemo"</span>&gt;</span><span class="tag">&lt;/<span class="name">dubbo:service</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>接口实现类</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> service.DemoService;</span><br><span class="line"> </span><br><span class="line"><span class="comment">//public class DemoSayImp implements DemoSay&#123;</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DemoSayImp</span> <span class="keyword">implements</span> <span class="title">DemoService</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">say</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">"this is my say"</span>);</span><br><span class="line">        <span class="keyword">return</span> <span class="string">"sdfsdf"</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>服务启动入口</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> org.springframework.context.support.ClassPathXmlApplicationContext;</span><br><span class="line"> </span><br><span class="line"><span class="keyword">import</span> java.io.IOException;</span><br><span class="line"> </span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Main</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        ClassPathXmlApplicationContext applicationContext =</span><br><span class="line">                <span class="keyword">new</span> ClassPathXmlApplicationContext(<span class="string">"bean.xml"</span>);</span><br><span class="line">        applicationContext.start();</span><br><span class="line">        <span class="keyword">try</span> &#123;</span><br><span class="line">            System.in.read();</span><br><span class="line">        &#125; <span class="keyword">catch</span> (IOException e) &#123;</span><br><span class="line">            e.printStackTrace();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>注意：linux系统需要修改/etc/hosts文件将hostname对应的ip地址改成现在电脑对应网卡的ip地址</p>
<ol start="3">
<li>consumer 消费者</li>
</ol>
<blockquote>
<p>xml配置文件</p>
</blockquote>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span><br><span class="line"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">xmlns:xsi</span>=<span class="string">"http://www.w3.org/2001/XMLSchema-instance"</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xmlns:dubbo</span>=<span class="string">"http://code.alibabatech.com/schema/dubbo"</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xmlns</span>=<span class="string">"http://www.springframework.org/schema/beans"</span></span></span><br><span class="line"><span class="tag">       <span class="attr">xsi:schemaLocation</span>=<span class="string">"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd</span></span></span><br><span class="line"><span class="tag"><span class="string">	http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dubbo:application</span> <span class="attr">name</span>=<span class="string">"consumer"</span>&gt;</span><span class="tag">&lt;/<span class="name">dubbo:application</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dubbo:registry</span> <span class="attr">address</span>=<span class="string">"multicast://224.5.6.10:1253"</span>/&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dubbo:reference</span> <span class="attr">interface</span>=<span class="string">"service.DemoService"</span> <span class="attr">id</span>=<span class="string">"demoService"</span>&gt;</span><span class="tag">&lt;/<span class="name">dubbo:reference</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>消费者程序入口</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> org.springframework.context.support.ClassPathXmlApplicationContext;</span><br><span class="line"><span class="keyword">import</span> service.DemoService;</span><br><span class="line"> </span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Main</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        ClassPathXmlApplicationContext context = <span class="keyword">new</span> ClassPathXmlApplicationContext(<span class="keyword">new</span> String[]&#123;<span class="string">"bean.xml"</span>&#125;);</span><br><span class="line">        <span class="comment">//context.start();</span></span><br><span class="line">        DemoService demoService = (DemoService) context.getBean(<span class="string">"demoService"</span>); <span class="comment">// 获取远程服务代理</span></span><br><span class="line">        String hello = demoService.say(); <span class="comment">// 执行远程方法</span></span><br><span class="line">        System.out.println(hello); <span class="comment">// 显示调用结果</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

          
        
      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </div>
  
  
  
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/2018/10/09/dubbo学习和使用（四）dubbo功能（2）/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="kyssion">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="kyssion-blog">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
                
                <a class="post-title-link" href="/2018/10/09/dubbo学习和使用（四）dubbo功能（2）/" itemprop="url">未命名</a></h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2018-10-09T15:22:37+08:00">
                2018-10-09
              </time>
            

            

            
          </span>

          

          
            
          

          
          

          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <h2 id="泛化调用客户端"><a href="#泛化调用客户端" class="headerlink" title="泛化调用客户端"></a>泛化调用客户端</h2><p>泛化接口调用方式主要用于客户端没有 API 接口及模型类元的情况，参数及返回值中的所有 POJO 均用 Map 表示，通常用于框架集成，比如：实现一个通用的服务测试框架，可通过 GenericService 调用所有服务实现。</p>
<p>通过 Spring 使用泛化调用<br>在 Spring 配置申明 generic=”true”：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:reference</span> <span class="attr">id</span>=<span class="string">"barService"</span> <span class="attr">interface</span>=<span class="string">"com.foo.BarService"</span> <span class="attr">generic</span>=<span class="string">"true"</span> /&gt;</span></span><br></pre></td></tr></table></figure>
<p>在 Java 代码获取 barService 并开始泛化调用：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">GenericService barService = (GenericService) applicationContext.getBean(<span class="string">"barService"</span>);</span><br><span class="line">Object result = barService.$invoke(<span class="string">"sayHello"</span>, <span class="keyword">new</span> String[] &#123; <span class="string">"java.lang.String"</span> &#125;, <span class="keyword">new</span> Object[] &#123; <span class="string">"World"</span> &#125;);</span><br></pre></td></tr></table></figure>
<blockquote>
<p>通过 API 方式使用泛化调用</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> com.alibaba.dubbo.rpc.service.GenericService; </span><br><span class="line">... </span><br><span class="line"> </span><br><span class="line"><span class="comment">// 引用远程服务 </span></span><br><span class="line"><span class="comment">// 该实例很重量，里面封装了所有与注册中心及服务提供方连接，请缓存</span></span><br><span class="line">ReferenceConfig&lt;GenericService&gt; reference = <span class="keyword">new</span> ReferenceConfig&lt;GenericService&gt;(); </span><br><span class="line"><span class="comment">// 弱类型接口名</span></span><br><span class="line">reference.setInterface(<span class="string">"com.xxx.XxxService"</span>);  </span><br><span class="line">reference.setVersion(<span class="string">"1.0.0"</span>);</span><br><span class="line"><span class="comment">// 声明为泛化接口 </span></span><br><span class="line">reference.setGeneric(<span class="keyword">true</span>);  </span><br><span class="line"></span><br><span class="line"><span class="comment">// 用com.alibaba.dubbo.rpc.service.GenericService可以替代所有接口引用  </span></span><br><span class="line">GenericService genericService = reference.get(); </span><br><span class="line"> </span><br><span class="line"><span class="comment">// 基本类型以及Date,List,Map等不需要转换，直接调用 </span></span><br><span class="line">Object result = genericService.$invoke(<span class="string">"sayHello"</span>, <span class="keyword">new</span> String[] &#123;<span class="string">"java.lang.String"</span>&#125;, <span class="keyword">new</span> Object[] &#123;<span class="string">"world"</span>&#125;); </span><br><span class="line"> </span><br><span class="line"><span class="comment">// 用Map表示POJO参数，如果返回值为POJO也将自动转成Map </span></span><br><span class="line">Map&lt;String, Object&gt; person = <span class="keyword">new</span> HashMap&lt;String, Object&gt;(); </span><br><span class="line">person.put(<span class="string">"name"</span>, <span class="string">"xxx"</span>); </span><br><span class="line">person.put(<span class="string">"password"</span>, <span class="string">"yyy"</span>); </span><br><span class="line"><span class="comment">// 如果返回POJO将自动转成Map </span></span><br><span class="line">Object result = genericService.$invoke(<span class="string">"findPerson"</span>, <span class="keyword">new</span> String[]</span><br><span class="line">&#123;<span class="string">"com.xxx.Person"</span>&#125;, <span class="keyword">new</span> Object[]&#123;person&#125;);</span><br></pre></td></tr></table></figure>
<blockquote>
<p>有关泛化类型的进一步解释</p>
</blockquote>
<p>假设存在 POJO 如：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.xxx;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">PersonImpl</span> <span class="keyword">implements</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> String name;</span><br><span class="line">    <span class="keyword">private</span> String password;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">getName</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> name;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setName</span><span class="params">(String name)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.name = name;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">getPassword</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> password;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setPassword</span><span class="params">(String password)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.password = password;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>则 POJO 数据：</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">Person person = <span class="keyword">new</span> PersonImpl(); </span><br><span class="line">person.setName(<span class="string">"xxx"</span>); </span><br><span class="line">person.setPassword(<span class="string">"yyy"</span>);</span><br></pre></td></tr></table></figure>
<p>可用下面 Map 表示：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">Map&lt;String, Object&gt; map = <span class="keyword">new</span> HashMap&lt;String, Object&gt;(); </span><br><span class="line"><span class="comment">// 注意：如果参数类型是接口，或者List等丢失泛型，可通过class属性指定类型。</span></span><br><span class="line">map.put(<span class="string">"class"</span>, <span class="string">"com.xxx.PersonImpl"</span>); </span><br><span class="line">map.put(<span class="string">"name"</span>, <span class="string">"xxx"</span>); </span><br><span class="line">map.put(<span class="string">"password"</span>, <span class="string">"yyy"</span>);</span><br></pre></td></tr></table></figure>
<h2 id="泛化调用服务端"><a href="#泛化调用服务端" class="headerlink" title="泛化调用服务端"></a>泛化调用服务端</h2><p>泛接口实现方式主要用于服务器端没有API接口及模型类元的情况，参数及返回值中的所有POJO均用Map表示，通常用于框架集成，比如：实现一个通用的远程服务Mock框架，可通过实现GenericService接口处理所有服务请求。</p>
<p>在 Java 代码中实现 GenericService 接口：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.foo;</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">MyGenericService</span> <span class="keyword">implements</span> <span class="title">GenericService</span> </span>&#123;</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">public</span> Object $invoke(String methodName, String[] parameterTypes, Object[] args) <span class="keyword">throws</span> GenericException &#123;</span><br><span class="line">        <span class="keyword">if</span> (<span class="string">"sayHello"</span>.equals(methodName)) &#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="string">"Welcome "</span> + args[<span class="number">0</span>];</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>通过 Spring 暴露泛化实现<br>在 Spring 配置申明服务的实现：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"genericService"</span> <span class="attr">class</span>=<span class="string">"com.foo.MyGenericService"</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dubbo:service</span> <span class="attr">interface</span>=<span class="string">"com.foo.BarService"</span> <span class="attr">ref</span>=<span class="string">"genericService"</span> /&gt;</span></span><br></pre></td></tr></table></figure>
<p>通过 API 方式暴露泛化实现</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 用com.alibaba.dubbo.rpc.service.GenericService可以替代所有接口实现 </span></span><br><span class="line">GenericService xxxService = <span class="keyword">new</span> XxxGenericService(); </span><br><span class="line"></span><br><span class="line"><span class="comment">// 该实例很重量，里面封装了所有与注册中心及服务提供方连接，请缓存 </span></span><br><span class="line">ServiceConfig&lt;GenericService&gt; service = <span class="keyword">new</span> ServiceConfig&lt;GenericService&gt;();</span><br><span class="line"><span class="comment">// 弱类型接口名 </span></span><br><span class="line">service.setInterface(<span class="string">"com.xxx.XxxService"</span>);  </span><br><span class="line">service.setVersion(<span class="string">"1.0.0"</span>); </span><br><span class="line"><span class="comment">// 指向一个通用服务实现 </span></span><br><span class="line">service.setRef(xxxService); </span><br><span class="line"> </span><br><span class="line"><span class="comment">// 暴露及注册服务 </span></span><br><span class="line">service.export();</span><br></pre></td></tr></table></figure>
<h2 id="回声测试"><a href="#回声测试" class="headerlink" title="回声测试"></a>回声测试</h2><p>回声测试用于检测服务是否可用，回声测试按照正常请求流程执行，能够测试整个调用是否通畅，可用于监控。</p>
<p>所有服务自动实现 EchoService 接口，只需将任意服务引用强制转型为 EchoService，即可使用。</p>
<p>Spring 配置：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:reference</span> <span class="attr">id</span>=<span class="string">"memberService"</span> <span class="attr">interface</span>=<span class="string">"com.xxx.MemberService"</span> /&gt;</span></span><br></pre></td></tr></table></figure>
<p>代码：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 远程服务引用</span></span><br><span class="line">MemberService memberService = ctx.getBean(<span class="string">"memberService"</span>); </span><br><span class="line"> </span><br><span class="line">EchoService echoService = (EchoService) memberService; <span class="comment">// 强制转型为EchoService</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 回声测试可用性</span></span><br><span class="line">String status = echoService.$echo(<span class="string">"OK"</span>); </span><br><span class="line"> </span><br><span class="line"><span class="keyword">assert</span>(status.equals(<span class="string">"OK"</span>));</span><br></pre></td></tr></table></figure>
<h2 id="上下文信息"><a href="#上下文信息" class="headerlink" title="上下文信息"></a>上下文信息</h2><p>上下文中存放的是当前调用过程中所需的环境信息。所有配置信息都将转换为 URL 的参数，参见 schema 配置参考手册 中的对应URL参数一列。</p>
<p>RpcContext 是一个 ThreadLocal 的临时状态记录器，当接收到 RPC 请求，或发起 RPC 请求时，RpcContext 的状态都会变化。比如：A 调 B，B 再调 C，则 B 机器上，在 B 调 C 之前，RpcContext 记录的是 A 调 B 的信息，在 B 调 C 之后，RpcContext 记录的是 B 调 C 的信息。</p>
<p>服务消费方</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 远程调用</span></span><br><span class="line">xxxService.xxx();</span><br><span class="line"><span class="comment">// 本端是否为消费端，这里会返回true</span></span><br><span class="line"><span class="keyword">boolean</span> isConsumerSide = RpcContext.getContext().isConsumerSide();</span><br><span class="line"><span class="comment">// 获取最后一次调用的提供方IP地址</span></span><br><span class="line">String serverIP = RpcContext.getContext().getRemoteHost();</span><br><span class="line"><span class="comment">// 获取当前服务配置信息，所有配置信息都将转换为URL的参数</span></span><br><span class="line">String application = RpcContext.getContext().getUrl().getParameter(<span class="string">"application"</span>);</span><br><span class="line"><span class="comment">// 注意：每发起RPC调用，上下文状态会变化</span></span><br><span class="line">yyyService.yyy();</span><br></pre></td></tr></table></figure>
<p>服务提供方<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">XxxServiceImpl</span> <span class="keyword">implements</span> <span class="title">XxxService</span> </span>&#123;</span><br><span class="line"> </span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">xxx</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="comment">// 本端是否为提供端，这里会返回true</span></span><br><span class="line">        <span class="keyword">boolean</span> isProviderSide = RpcContext.getContext().isProviderSide();</span><br><span class="line">        <span class="comment">// 获取调用方IP地址</span></span><br><span class="line">        String clientIP = RpcContext.getContext().getRemoteHost();</span><br><span class="line">        <span class="comment">// 获取当前服务配置信息，所有配置信息都将转换为URL的参数</span></span><br><span class="line">        String application = RpcContext.getContext().getUrl().getParameter(<span class="string">"application"</span>);</span><br><span class="line">        <span class="comment">// 注意：每发起RPC调用，上下文状态会变化</span></span><br><span class="line">        yyyService.yyy();</span><br><span class="line">        <span class="comment">// 此时本端变成消费端，这里会返回false</span></span><br><span class="line">        <span class="keyword">boolean</span> isProviderSide = RpcContext.getContext().isProviderSide();</span><br><span class="line">    &#125; </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h2 id="隐式参数"><a href="#隐式参数" class="headerlink" title="隐式参数"></a>隐式参数</h2><p>可以通过 RpcContext 上的 setAttachment 和 getAttachment 在服务消费方和提供方之间进行参数的隐式传递。 [1]</p>
<p><img src="blogimg/dubbo/n7.png" alt=""></p>
<p>在服务消费方端设置隐式参数<br>setAttachment 设置的 KV 对，在完成下面一次远程调用会被清空，即多次远程调用要多次设置。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">RpcContext.getContext().setAttachment(<span class="string">"index"</span>, <span class="string">"1"</span>); <span class="comment">// 隐式传参，后面的远程调用都会隐式将这些参数发送到服务器端，类似cookie，用于框架集成，不建议常规业务使用</span></span><br><span class="line">xxxService.xxx(); <span class="comment">// 远程调用</span></span><br><span class="line"><span class="comment">// ...</span></span><br></pre></td></tr></table></figure>
<p>在服务提供方端获取隐式参数<br>public class XxxServiceImpl implements XxxService {</p>
<pre><code>public void xxx() {
    // 获取客户端隐式传入的参数，用于框架集成，不建议常规业务使用
    String index = RpcContext.getContext().getAttachment(&quot;index&quot;); 
}
</code></pre><p>}</p>
<h2 id="异步调用"><a href="#异步调用" class="headerlink" title="异步调用"></a>异步调用</h2><p>基于 NIO 的非阻塞实现并行调用，客户端不需要启动多线程即可完成并行调用多个远程服务，相对多线程开销较小。 [1]</p>
<p><img src="blogimg/dubbo/n8.png" alt=""></p>
<p>在 consumer.xml 中配置：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:reference</span> <span class="attr">id</span>=<span class="string">"fooService"</span> <span class="attr">interface</span>=<span class="string">"com.alibaba.foo.FooService"</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">dubbo:method</span> <span class="attr">name</span>=<span class="string">"findFoo"</span> <span class="attr">async</span>=<span class="string">"true"</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dubbo:reference</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dubbo:reference</span> <span class="attr">id</span>=<span class="string">"barService"</span> <span class="attr">interface</span>=<span class="string">"com.alibaba.bar.BarService"</span>&gt;</span></span><br><span class="line">      <span class="tag">&lt;<span class="name">dubbo:method</span> <span class="attr">name</span>=<span class="string">"findBar"</span> <span class="attr">async</span>=<span class="string">"true"</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dubbo:reference</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>调用代码:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 此调用会立即返回null</span></span><br><span class="line">fooService.findFoo(fooId);</span><br><span class="line"><span class="comment">// 拿到调用的Future引用，当结果返回后，会被通知和设置到此Future</span></span><br><span class="line">Future&lt;Foo&gt; fooFuture = RpcContext.getContext().getFuture(); </span><br><span class="line"> </span><br><span class="line"><span class="comment">// 此调用会立即返回null</span></span><br><span class="line">barService.findBar(barId);</span><br><span class="line"><span class="comment">// 拿到调用的Future引用，当结果返回后，会被通知和设置到此Future</span></span><br><span class="line">Future&lt;Bar&gt; barFuture = RpcContext.getContext().getFuture(); </span><br><span class="line"> </span><br><span class="line"><span class="comment">// 此时findFoo和findBar的请求同时在执行，客户端不需要启动多线程来支持并行，而是借助NIO的非阻塞完成</span></span><br><span class="line"> </span><br><span class="line"><span class="comment">// 如果foo已返回，直接拿到返回值，否则线程wait住，等待foo返回后，线程会被notify唤醒</span></span><br><span class="line">Foo foo = fooFuture.get(); </span><br><span class="line"><span class="comment">// 同理等待bar返回</span></span><br><span class="line">Bar bar = barFuture.get(); </span><br><span class="line"> </span><br><span class="line"><span class="comment">// 如果foo需要5秒返回，bar需要6秒返回，实际只需等6秒，即可获取到foo和bar，进行接下来的处理。</span></span><br></pre></td></tr></table></figure>
<p>你也可以设置是否等待消息发出： [2]</p>
<p>sent=”true” 等待消息发出，消息发送失败将抛出异常。<br>sent=”false” 不等待消息发出，将消息放入 IO 队列，即刻返回。</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:method</span> <span class="attr">name</span>=<span class="string">"findFoo"</span> <span class="attr">async</span>=<span class="string">"true"</span> <span class="attr">sent</span>=<span class="string">"true"</span> /&gt;</span></span><br></pre></td></tr></table></figure>
<p>如果你只是想异步，完全忽略返回值，可以配置 return=”false”，以减少 Future 对象的创建和管理成本：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:method</span> <span class="attr">name</span>=<span class="string">"findFoo"</span> <span class="attr">async</span>=<span class="string">"true"</span> <span class="attr">return</span>=<span class="string">"false"</span> /&gt;</span></span><br></pre></td></tr></table></figure>
<h2 id="本地调用"><a href="#本地调用" class="headerlink" title="本地调用"></a>本地调用</h2><p>本地调用使用了 injvm 协议，是一个伪协议，它不开启端口，不发起远程调用，只在 JVM 内直接关联，但执行 Dubbo 的 Filter 链。</p>
<blockquote>
<p>配置</p>
</blockquote>
<p>定义 injvm 协议</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:protocol</span> <span class="attr">name</span>=<span class="string">"injvm"</span> /&gt;</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>设置默认协议</p>
</blockquote>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:provider</span> <span class="attr">protocol</span>=<span class="string">"injvm"</span> /&gt;</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>设置服务协议</p>
</blockquote>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:service</span> <span class="attr">protocol</span>=<span class="string">"injvm"</span> /&gt;</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>优先使用 injvm</p>
</blockquote>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:consumer</span> <span class="attr">injvm</span>=<span class="string">"true"</span> <span class="attr">...</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dubbo:provider</span> <span class="attr">injvm</span>=<span class="string">"true"</span> <span class="attr">...</span>/&gt;</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>或</p>
</blockquote>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:reference</span> <span class="attr">injvm</span>=<span class="string">"true"</span> <span class="attr">...</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dubbo:service</span> <span class="attr">injvm</span>=<span class="string">"true"</span> <span class="attr">...</span>/&gt;</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>注意：服务暴露与服务引用都需要声明 injvm=”true”</p>
</blockquote>
<p>自动暴露、引用本地服务<br>从 2.2.0 开始，每个服务默认都会在本地暴露。在引用服务的时候，默认优先引用本地服务。如果希望引用远程服务可以使用一下配置强制引用远程服务。</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:reference</span> <span class="attr">...</span> <span class="attr">scope</span>=<span class="string">"remote"</span> /&gt;</span></span><br></pre></td></tr></table></figure>
          
        
      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </div>
  
  
  
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/2018/10/09/dubbo学习和使用（二）使用初探和配置方法/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="kyssion">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="kyssion-blog">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
                
                <a class="post-title-link" href="/2018/10/09/dubbo学习和使用（二）使用初探和配置方法/" itemprop="url">未命名</a></h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2018-10-09T15:22:37+08:00">
                2018-10-09
              </time>
            

            

            
          </span>

          

          
            
          

          
          

          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <h3 id="快速启动"><a href="#快速启动" class="headerlink" title="快速启动"></a>快速启动</h3><p>Dubbo 采用全 Spring 配置方式，透明化接入应用，对应用没有任何 API 侵入，只需用 Spring 加载 Dubbo 的配置即可，Dubbo 基于 Spring 的 Schema 扩展进行加载。</p>
<p>如果不想使用 Spring 配置，可以通过 API 的方式 进行调用。</p>
<h3 id="服务提供者"><a href="#服务提供者" class="headerlink" title="服务提供者"></a>服务提供者</h3><blockquote>
<p>定义服务接口 DemoService.java：</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.kys.dubbo.demo;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">DemoService</span> </span>&#123;</span><br><span class="line">    <span class="function">String <span class="title">sayHello</span><span class="params">(String name)</span></span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>在服务提供方实现接口DemoServiceImpl.java：</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.alibaba.dubbo.demo.provider;</span><br><span class="line"> </span><br><span class="line"><span class="keyword">import</span> com.alibaba.dubbo.demo.DemoService;</span><br><span class="line"> </span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DemoServiceImpl</span> <span class="keyword">implements</span> <span class="title">DemoService</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">sayHello</span><span class="params">(String name)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">"Hello "</span> + name;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>用 Spring 配置声明暴露服务provider.xml：</p>
</blockquote>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span><br><span class="line"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">"http://www.springframework.org/schema/beans"</span></span></span><br><span class="line"><span class="tag">    <span class="attr">xmlns:xsi</span>=<span class="string">"http://www.w3.org/2001/XMLSchema-instance"</span></span></span><br><span class="line"><span class="tag">    <span class="attr">xmlns:dubbo</span>=<span class="string">"http://dubbo.apache.org/schema/dubbo"</span></span></span><br><span class="line"><span class="tag">    <span class="attr">xsi:schemaLocation</span>=<span class="string">"http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans-4.3.xsd        http://dubbo.apache.org/schema/dubbo        http://dubbo.apache.org/schema/dubbo/dubbo.xsd"</span>&gt;</span></span><br><span class="line"> </span><br><span class="line">    <span class="comment">&lt;!-- 提供方应用信息，用于计算依赖关系 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dubbo:application</span> <span class="attr">name</span>=<span class="string">"hello-world-app"</span>  /&gt;</span></span><br><span class="line"> </span><br><span class="line">    <span class="comment">&lt;!-- 使用multicast广播注册中心暴露服务地址 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dubbo:registry</span> <span class="attr">address</span>=<span class="string">"multicast://224.5.6.7:1234"</span> /&gt;</span></span><br><span class="line"> </span><br><span class="line">    <span class="comment">&lt;!-- 用dubbo协议在20880端口暴露服务 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dubbo:protocol</span> <span class="attr">name</span>=<span class="string">"dubbo"</span> <span class="attr">port</span>=<span class="string">"20880"</span> /&gt;</span></span><br><span class="line"> </span><br><span class="line">    <span class="comment">&lt;!-- 声明需要暴露的服务接口 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dubbo:service</span> <span class="attr">interface</span>=<span class="string">"com.alibaba.dubbo.demo.DemoService"</span> <span class="attr">ref</span>=<span class="string">"demoService"</span> /&gt;</span></span><br><span class="line"> </span><br><span class="line">    <span class="comment">&lt;!-- 和本地bean一样实现服务 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"demoService"</span> <span class="attr">class</span>=<span class="string">"com.alibaba.dubbo.demo.provider.DemoServiceImpl"</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>加载 Spring 配置Provider.java：</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> org.springframework.context.support.ClassPathXmlApplicationContext;</span><br><span class="line"> </span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Provider</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        ClassPathXmlApplicationContext context = <span class="keyword">new</span> ClassPathXmlApplicationContext(<span class="keyword">new</span> String[] &#123;<span class="string">"http://10.20.160.198/wiki/display/dubbo/provider.xml"</span>&#125;);</span><br><span class="line">        context.start();</span><br><span class="line">        System.in.read(); <span class="comment">// 按任意键退出</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="服务消费者"><a href="#服务消费者" class="headerlink" title="服务消费者"></a>服务消费者</h3><blockquote>
<p>通过 Spring 配置引用远程服务consumer.xml：</p>
</blockquote>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span><br><span class="line"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">"http://www.springframework.org/schema/beans"</span></span></span><br><span class="line"><span class="tag">    <span class="attr">xmlns:xsi</span>=<span class="string">"http://www.w3.org/2001/XMLSchema-instance"</span></span></span><br><span class="line"><span class="tag">    <span class="attr">xmlns:dubbo</span>=<span class="string">"http://dubbo.apache.org/schema/dubbo"</span></span></span><br><span class="line"><span class="tag">    <span class="attr">xsi:schemaLocation</span>=<span class="string">"http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans-4.3.xsd        http://dubbo.apache.org/schema/dubbo        http://dubbo.apache.org/schema/dubbo/dubbo.xsd"</span>&gt;</span></span><br><span class="line"> </span><br><span class="line">    <span class="comment">&lt;!-- 消费方应用名，用于计算依赖关系，不是匹配条件，不要与提供方一样 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dubbo:application</span> <span class="attr">name</span>=<span class="string">"consumer-of-helloworld-app"</span>  /&gt;</span></span><br><span class="line"> </span><br><span class="line">    <span class="comment">&lt;!-- 使用multicast广播注册中心暴露发现服务地址 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dubbo:registry</span> <span class="attr">address</span>=<span class="string">"multicast://224.5.6.7:1234"</span> /&gt;</span></span><br><span class="line"> </span><br><span class="line">    <span class="comment">&lt;!-- 生成远程服务代理，可以和本地bean一样使用demoService --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dubbo:reference</span> <span class="attr">id</span>=<span class="string">"demoService"</span> <span class="attr">interface</span>=<span class="string">"com.alibaba.dubbo.demo.DemoService"</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>加载Spring配置，并调用远程服务Consumer.java：</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> org.springframework.context.support.ClassPathXmlApplicationContext;</span><br><span class="line"><span class="keyword">import</span> com.alibaba.dubbo.demo.DemoService;</span><br><span class="line"> </span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Consumer</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> Exception </span>&#123;</span><br><span class="line">        ClassPathXmlApplicationContext context = <span class="keyword">new</span> ClassPathXmlApplicationContext(<span class="keyword">new</span> String[] &#123;<span class="string">"http://10.20.160.198/wiki/display/dubbo/consumer.xml"</span>&#125;);</span><br><span class="line">        context.start();</span><br><span class="line">        DemoService demoService = (DemoService)context.getBean(<span class="string">"demoService"</span>); <span class="comment">// 获取远程服务代理</span></span><br><span class="line">        String hello = demoService.sayHello(<span class="string">"world"</span>); <span class="comment">// 执行远程方法</span></span><br><span class="line">        System.out.println( hello ); <span class="comment">// 显示调用结果</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="dubbo-的四中配置方式"><a href="#dubbo-的四中配置方式" class="headerlink" title="dubbo 的四中配置方式"></a>dubbo 的四中配置方式</h3><h4 id="xml-配置方法"><a href="#xml-配置方法" class="headerlink" title="xml　配置方法"></a>xml　配置方法</h4><p>配置实例</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span><br><span class="line"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">"http://www.springframework.org/schema/beans"</span></span></span><br><span class="line"><span class="tag">    <span class="attr">xmlns:xsi</span>=<span class="string">"http://www.w3.org/2001/XMLSchema-instance"</span></span></span><br><span class="line"><span class="tag">    <span class="attr">xmlns:dubbo</span>=<span class="string">"http://dubbo.apache.org/schema/dubbo"</span></span></span><br><span class="line"><span class="tag">    <span class="attr">xsi:schemaLocation</span>=<span class="string">"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd"</span>&gt;</span>  </span><br><span class="line">    <span class="tag">&lt;<span class="name">dubbo:application</span> <span class="attr">name</span>=<span class="string">"hello-world-app"</span>  /&gt;</span>  </span><br><span class="line">    <span class="tag">&lt;<span class="name">dubbo:registry</span> <span class="attr">address</span>=<span class="string">"multicast://224.5.6.7:1234"</span> /&gt;</span>  </span><br><span class="line">    <span class="tag">&lt;<span class="name">dubbo:protocol</span> <span class="attr">name</span>=<span class="string">"dubbo"</span> <span class="attr">port</span>=<span class="string">"20880"</span> /&gt;</span>  </span><br><span class="line">    <span class="tag">&lt;<span class="name">dubbo:service</span> <span class="attr">interface</span>=<span class="string">"com.alibaba.dubbo.demo.DemoService"</span> <span class="attr">ref</span>=<span class="string">"demoServiceLocal"</span> /&gt;</span>  </span><br><span class="line">    <span class="tag">&lt;<span class="name">dubbo:reference</span> <span class="attr">id</span>=<span class="string">"demoServiceRemote"</span> <span class="attr">interface</span>=<span class="string">"com.alibaba.dubbo.demo.DemoService"</span> /&gt;</span>  </span><br><span class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>所有标签都支持自定义参数，用于不同扩展点实现的特殊配置，如：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:protocol</span> <span class="attr">name</span>=<span class="string">"jms"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dubbo:parameter</span> <span class="attr">key</span>=<span class="string">"queue"</span> <span class="attr">value</span>=<span class="string">"your_queue"</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dubbo:protocol</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!--或者使用缩进的方法--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dubbo:protocol</span> <span class="attr">name</span>=<span class="string">"jms"</span> <span class="attr">p:queue</span>=<span class="string">"your_queue"</span> /&gt;</span></span><br></pre></td></tr></table></figure>
<p>dubbo 所有的标签和作用</p>
<table>
<thead>
<tr>
<th>标签</th>
<th>用途</th>
<th>解释</th>
</tr>
</thead>
<tbody>
<tr>
<td><a href="dubbo:service/" target="_blank" rel="noopener">dubbo:service/</a></td>
<td>服务配置</td>
<td>用于暴露一个服务，定义服务的元信息，一个服务可以用多个协议暴露，一个服务也可以注册到多个注册中心</td>
</tr>
<tr>
<td><a href="dubbo:reference/" target="_blank" rel="noopener">dubbo:reference/</a></td>
<td>引用配置</td>
<td>用于创建一个远程服务代理，一个引用可以指向多个注册中心</td>
</tr>
<tr>
<td><a href="dubbo:protocol/" target="_blank" rel="noopener">dubbo:protocol/</a></td>
<td>协议配置</td>
<td>用于配置提供服务的协议信息，协议由提供方指定，消费方被动接受</td>
</tr>
<tr>
<td><a href="dubbo:application/" target="_blank" rel="noopener">dubbo:application/</a></td>
<td>应用配置</td>
<td>用于配置当前应用信息，不管该应用是提供者还是消费者</td>
</tr>
<tr>
<td><a href="dubbo:module/" target="_blank" rel="noopener">dubbo:module/</a></td>
<td>模块配置</td>
<td>用于配置当前模块信息，可选</td>
</tr>
<tr>
<td><a href="dubbo:registry/" target="_blank" rel="noopener">dubbo:registry/</a></td>
<td>注册中心配置</td>
<td>用于配置连接注册中心相关信息</td>
</tr>
<tr>
<td><a href="dubbo:monitor/" target="_blank" rel="noopener">dubbo:monitor/</a></td>
<td>监控中心配置</td>
<td>用于配置连接监控中心相关信息，可选</td>
</tr>
<tr>
<td><a href="dubbo:provider/" target="_blank" rel="noopener">dubbo:provider/</a></td>
<td>提供方配置</td>
<td>当 ProtocolConfig 和 ServiceConfig 某属性没有配置时，采用此缺省值，可选</td>
</tr>
<tr>
<td><a href="dubbo:consumer/" target="_blank" rel="noopener">dubbo:consumer/</a></td>
<td>消费方配置</td>
<td>当 ReferenceConfig 某属性没有配置时，采用此缺省值，可选</td>
</tr>
<tr>
<td><a href="dubbo:method/" target="_blank" rel="noopener">dubbo:method/</a></td>
<td>方法配置</td>
<td>用于 ServiceConfig 和 ReferenceConfig 指定方法级的配置信息</td>
</tr>
<tr>
<td><a href="dubbo:argument/" target="_blank" rel="noopener">dubbo:argument/</a></td>
<td>参数配置</td>
<td>用于指定方法参数配置</td>
</tr>
</tbody>
</table>
<blockquote>
<p>配置覆盖关系</p>
</blockquote>
<p>以 timeout 为例，显示了配置的查找顺序，其它 retries, loadbalance, actives 等类似：</p>
<ul>
<li>方法级优先，接口级次之，全局配置再次之。</li>
<li>如果级别一样，则消费方优先，提供方次之。</li>
</ul>
<p>其中，服务提供方配置，通过 URL 经由注册中心传递给消费方。</p>
<blockquote>
<p>从上到下优先级递减</p>
</blockquote>
<p><img src="blogimg/dubbo/n2.png" alt=""></p>
<h4 id="属性配置"><a href="#属性配置" class="headerlink" title="属性配置"></a>属性配置</h4><p>如果公共配置很简单，没有多注册中心，多协议等情况，或者想多个 Spring 容器想共享配置，可以使用 dubbo.properties 作为缺省配置。</p>
<p>映射规则<br>将 XML 配置的标签名，加属性名，用点分隔，多个属性拆成多行</p>
<ul>
<li>比如：dubbo.application.name=foo等价于&lt;dubbo:application name=”foo” /&gt;</li>
<li><p>比如：dubbo.registry.address=10.20.153.10:9090等价于&lt;dubbo:registry address=”10.20.153.10:9090” /&gt;<br>如果 XML 有多行同名标签配置，可用 id 号区分，如果没有 id 号将对所有同名标签生效</p>
</li>
<li><p>比如：dubbo.protocol.rmi.port=1234等价于&lt;dubbo:protocol id=”rmi” name=”rmi” port=”1099” /&gt; [2]</p>
</li>
<li>比如：dubbo.registry.china.address=10.20.153.10:9090等价于&lt;dubbo:registry id=”china” address=”10.20.153.10:9090” /&gt;<br>下面是 dubbo.properties 的一个典型配置：</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">dubbo.application.name=foo</span><br><span class="line">dubbo.application.owner=bar</span><br><span class="line">dubbo.registry.address=10.20.153.10:9090</span><br></pre></td></tr></table></figure>
<blockquote>
<p>覆盖策略（从上到下优先级递减）</p>
</blockquote>
<p><img src="blogimg/dubbo/n3.png" alt=""></p>
<ul>
<li><p>如果 classpath 根目录下存在多个 dubbo.properties，比如多个 jar 包中有 dubbo.properties，Dubbo 会任意加载，并打印 Error 日志，后续可能改为抛异常。</p>
</li>
<li><p>协议的 id 没配时，缺省使用协议名作为 id</p>
</li>
</ul>
<h4 id="api-配置"><a href="#api-配置" class="headerlink" title="api 配置"></a>api 配置</h4><p>API 属性xml与配置项一对一</p>
<blockquote>
<p>服务提供者</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> com.alibaba.dubbo.rpc.config.ApplicationConfig;</span><br><span class="line"><span class="keyword">import</span> com.alibaba.dubbo.rpc.config.RegistryConfig;</span><br><span class="line"><span class="keyword">import</span> com.alibaba.dubbo.rpc.config.ProviderConfig;</span><br><span class="line"><span class="keyword">import</span> com.alibaba.dubbo.rpc.config.ServiceConfig;</span><br><span class="line"><span class="keyword">import</span> com.xxx.XxxService;</span><br><span class="line"><span class="keyword">import</span> com.xxx.XxxServiceImpl;</span><br><span class="line"> </span><br><span class="line"><span class="comment">// 服务实现</span></span><br><span class="line">XxxService xxxService = <span class="keyword">new</span> XxxServiceImpl();</span><br><span class="line"> </span><br><span class="line"><span class="comment">// 当前应用配置</span></span><br><span class="line">ApplicationConfig application = <span class="keyword">new</span> ApplicationConfig();</span><br><span class="line">application.setName(<span class="string">"xxx"</span>);</span><br><span class="line"> </span><br><span class="line"><span class="comment">// 连接注册中心配置</span></span><br><span class="line">RegistryConfig registry = <span class="keyword">new</span> RegistryConfig();</span><br><span class="line">registry.setAddress(<span class="string">"10.20.130.230:9090"</span>);</span><br><span class="line">registry.setUsername(<span class="string">"aaa"</span>);</span><br><span class="line">registry.setPassword(<span class="string">"bbb"</span>);</span><br><span class="line"> </span><br><span class="line"><span class="comment">// 服务提供者协议配置</span></span><br><span class="line">ProtocolConfig protocol = <span class="keyword">new</span> ProtocolConfig();</span><br><span class="line">protocol.setName(<span class="string">"dubbo"</span>);</span><br><span class="line">protocol.setPort(<span class="number">12345</span>);</span><br><span class="line">protocol.setThreads(<span class="number">200</span>);</span><br><span class="line"> </span><br><span class="line"><span class="comment">// 注意：ServiceConfig为重对象，内部封装了与注册中心的连接，以及开启服务端口</span></span><br><span class="line"> </span><br><span class="line"><span class="comment">// 服务提供者暴露服务配置</span></span><br><span class="line">ServiceConfig&lt;XxxService&gt; service = <span class="keyword">new</span> ServiceConfig&lt;XxxService&gt;(); <span class="comment">// 此实例很重，封装了与注册中心的连接，请自行缓存，否则可能造成内存和连接泄漏</span></span><br><span class="line">service.setApplication(application);</span><br><span class="line">service.setRegistry(registry); <span class="comment">// 多个注册中心可以用setRegistries()</span></span><br><span class="line">service.setProtocol(protocol); <span class="comment">// 多个协议可以用setProtocols()</span></span><br><span class="line">service.setInterface(XxxService.class);</span><br><span class="line">service.setRef(xxxService);</span><br><span class="line">service.setVersion(<span class="string">"1.0.0"</span>);</span><br><span class="line"> </span><br><span class="line"><span class="comment">// 暴露及注册服务</span></span><br><span class="line">service.export();</span><br></pre></td></tr></table></figure>
<blockquote>
<p>服务消费者</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> com.alibaba.dubbo.rpc.config.ApplicationConfig;</span><br><span class="line"><span class="keyword">import</span> com.alibaba.dubbo.rpc.config.RegistryConfig;</span><br><span class="line"><span class="keyword">import</span> com.alibaba.dubbo.rpc.config.ConsumerConfig;</span><br><span class="line"><span class="keyword">import</span> com.alibaba.dubbo.rpc.config.ReferenceConfig;</span><br><span class="line"><span class="keyword">import</span> com.xxx.XxxService;</span><br><span class="line"> </span><br><span class="line"><span class="comment">// 当前应用配置</span></span><br><span class="line">ApplicationConfig application = <span class="keyword">new</span> ApplicationConfig();</span><br><span class="line">application.setName(<span class="string">"yyy"</span>);</span><br><span class="line"> </span><br><span class="line"><span class="comment">// 连接注册中心配置</span></span><br><span class="line">RegistryConfig registry = <span class="keyword">new</span> RegistryConfig();</span><br><span class="line">registry.setAddress(<span class="string">"10.20.130.230:9090"</span>);</span><br><span class="line">registry.setUsername(<span class="string">"aaa"</span>);</span><br><span class="line">registry.setPassword(<span class="string">"bbb"</span>);</span><br><span class="line"> </span><br><span class="line"><span class="comment">// 注意：ReferenceConfig为重对象，内部封装了与注册中心的连接，以及与服务提供方的连接</span></span><br><span class="line"> </span><br><span class="line"><span class="comment">// 引用远程服务</span></span><br><span class="line">ReferenceConfig&lt;XxxService&gt; reference = <span class="keyword">new</span> ReferenceConfig&lt;XxxService&gt;(); <span class="comment">// 此实例很重，封装了与注册中心的连接以及与提供者的连接，请自行缓存，否则可能造成内存和连接泄漏</span></span><br><span class="line">reference.setApplication(application);</span><br><span class="line">reference.setRegistry(registry); <span class="comment">// 多个注册中心可以用setRegistries()</span></span><br><span class="line">reference.setInterface(XxxService.class);</span><br><span class="line">reference.setVersion(<span class="string">"1.0.0"</span>);</span><br><span class="line"> </span><br><span class="line"><span class="comment">// 和本地bean一样使用xxxService</span></span><br><span class="line">XxxService xxxService = reference.get(); <span class="comment">// 注意：此代理对象内部封装了所有通讯细节，对象较重，请缓存复用</span></span><br></pre></td></tr></table></figure>
<p>特殊场景<br>下面只列出不同的地方，其它参见上面的写法</p>
<blockquote>
<p>方法级设置</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 方法级配置</span></span><br><span class="line">List&lt;MethodConfig&gt; methods = <span class="keyword">new</span> ArrayList&lt;MethodConfig&gt;();</span><br><span class="line">MethodConfig method = <span class="keyword">new</span> MethodConfig();</span><br><span class="line">method.setName(<span class="string">"createXxx"</span>);</span><br><span class="line">method.setTimeout(<span class="number">10000</span>);</span><br><span class="line">method.setRetries(<span class="number">0</span>);</span><br><span class="line">methods.add(method);</span><br><span class="line"> </span><br><span class="line"><span class="comment">// 引用远程服务</span></span><br><span class="line">ReferenceConfig&lt;XxxService&gt; reference = <span class="keyword">new</span> ReferenceConfig&lt;XxxService&gt;(); <span class="comment">// 此实例很重，封装了与注册中心的连接以及与提供者的连接，请自行缓存，否则可能造成内存和连接泄漏</span></span><br><span class="line">reference.setMethods(methods); <span class="comment">// 设置方法级配置</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>点对点直连</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">ReferenceConfig&lt;XxxService&gt; reference = <span class="keyword">new</span> ReferenceConfig&lt;XxxService&gt;(); <span class="comment">// 此实例很重，封装了与注册中心的连接以及与提供者的连接，请自行缓存，否则可能造成内存和连接泄漏</span></span><br><span class="line"><span class="comment">// 如果点对点直连，可以用reference.setUrl()指定目标地址，设置url后将绕过注册中心，</span></span><br><span class="line"><span class="comment">// 其中，协议对应provider.setProtocol()的值，端口对应provider.setPort()的值，</span></span><br><span class="line"><span class="comment">// 路径对应service.setPath()的值，如果未设置path，缺省path为接口名</span></span><br><span class="line">reference.setUrl(<span class="string">"dubbo://10.20.130.230:20880/com.xxx.XxxService"</span>);</span><br></pre></td></tr></table></figure>
<p>API使用范围说明：API 仅用于 OpenAPI, ESB, Test, Mock 等系统集成，普通服务提供方或消费方，请采用XML 配置方式使用 Dubbo</p>
<h4 id="注解配置"><a href="#注解配置" class="headerlink" title="注解配置"></a>注解配置</h4><blockquote>
<p>服务提供方</p>
</blockquote>
<blockquote>
<p>Service注解暴露服务</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> com.alibaba.dubbo.config.annotation.Service;</span><br><span class="line"> </span><br><span class="line"><span class="meta">@Service</span>(timeout = <span class="number">5000</span>)</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">AnnotateServiceImpl</span> <span class="keyword">implements</span> <span class="title">AnnotateService</span> </span>&#123; </span><br><span class="line">    <span class="comment">// ...</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>javaconfig形式配置公共模块</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DubboConfiguration</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> ApplicationConfig <span class="title">applicationConfig</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        ApplicationConfig applicationConfig = <span class="keyword">new</span> ApplicationConfig();</span><br><span class="line">        applicationConfig.setName(<span class="string">"provider-test"</span>);</span><br><span class="line">        <span class="keyword">return</span> applicationConfig;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> RegistryConfig <span class="title">registryConfig</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        RegistryConfig registryConfig = <span class="keyword">new</span> RegistryConfig();</span><br><span class="line">        registryConfig.setAddress(<span class="string">"zookeeper://127.0.0.1:2181"</span>);</span><br><span class="line">        registryConfig.setClient(<span class="string">"curator"</span>);</span><br><span class="line">        <span class="keyword">return</span> registryConfig;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>指定dubbo扫描路径</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="meta">@DubboComponentScan</span>(basePackages = <span class="string">"com.alibaba.dubbo.test.service.impl"</span>)</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ProviderTestApp</span> </span>&#123;</span><br><span class="line">    <span class="comment">// ...</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>服务消费方</p>
</blockquote>
<blockquote>
<p>Reference注解引用服务</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">AnnotationConsumeService</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@com</span>.alibaba.dubbo.config.annotation.Reference</span><br><span class="line">    <span class="keyword">public</span> AnnotateService annotateService;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// ...</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>javaconfig形式配置公共模块</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Configuration</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DubboConfiguration</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> ApplicationConfig <span class="title">applicationConfig</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        ApplicationConfig applicationConfig = <span class="keyword">new</span> ApplicationConfig();</span><br><span class="line">        applicationConfig.setName(<span class="string">"consumer-test"</span>);</span><br><span class="line">        <span class="keyword">return</span> applicationConfig;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> ConsumerConfig <span class="title">consumerConfig</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        ConsumerConfig consumerConfig = <span class="keyword">new</span> ConsumerConfig();</span><br><span class="line">        consumerConfig.setTimeout(<span class="number">3000</span>);</span><br><span class="line">        <span class="keyword">return</span> consumerConfig;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Bean</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> RegistryConfig <span class="title">registryConfig</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        RegistryConfig registryConfig = <span class="keyword">new</span> RegistryConfig();</span><br><span class="line">        registryConfig.setAddress(<span class="string">"zookeeper://127.0.0.1:2181"</span>);</span><br><span class="line">        registryConfig.setClient(<span class="string">"curator"</span>);</span><br><span class="line">        <span class="keyword">return</span> registryConfig;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>指定dubbo扫描路径</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@SpringBootApplication</span></span><br><span class="line"><span class="meta">@DubboComponentScan</span>(basePackages = <span class="string">"com.alibaba.dubbo.test.service"</span>)</span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ConsumerTestApp</span> </span>&#123;</span><br><span class="line">    <span class="comment">// ...</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>注意</p>
</blockquote>
<blockquote>
<p>如果你曾使用旧版annotation配置，请删除所有相关配置，我们将在下个版本删除所有旧版配置项。</p>
</blockquote>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:annotation</span> <span class="attr">package</span>=<span class="string">"com.alibaba.dubbo.test.service"</span> /&gt;</span></span><br></pre></td></tr></table></figure>
          
        
      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </div>
  
  
  
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/2018/10/09/dubbo学习和使用（六）dubbo功能（4）-路由/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="kyssion">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="kyssion-blog">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
                
                <a class="post-title-link" href="/2018/10/09/dubbo学习和使用（六）dubbo功能（4）-路由/" itemprop="url">未命名</a></h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2018-10-09T15:22:37+08:00">
                2018-10-09
              </time>
            

            

            
          </span>

          

          
            
          

          
          

          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <h2 id="路由规则"><a href="#路由规则" class="headerlink" title="路由规则"></a>路由规则</h2><blockquote>
<p>路由规则决定一次 dubbo 服务调用的目标服务器，分为条件路由规则和脚本路由规则，并且支持可扩展。</p>
</blockquote>
<h3 id="写入路由规则"><a href="#写入路由规则" class="headerlink" title="写入路由规则"></a>写入路由规则</h3><p>向注册中心写入路由规则的操作通常由监控中心或治理中心的页面完成</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension();</span><br><span class="line">Registry registry = registryFactory.getRegistry(URL.valueOf(<span class="string">"zookeeper://10.20.153.10:2181"</span>));</span><br><span class="line">registry.register(URL.valueOf(<span class="string">"condition://0.0.0.0/com.foo.BarService?category=routers&amp;dynamic=false&amp;rule="</span> + URL.encode(<span class="string">"host = 10.20.153.10 =&gt; host = 10.20.153.11"</span>) + <span class="string">"));</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>属性解释</p>
</blockquote>
<ul>
<li>condition:// 表示路由规则的类型，支持条件路由规则和脚本路由规则，可扩展，必填。</li>
<li>0.0.0.0 表示对所有 IP 地址生效，如果只想对某个 IP 的生效，请填入具体 IP，必填。</li>
<li>com.foo.BarService 表示只对指定服务生效，必填。</li>
<li>group=foo 对指定服务的指定group生效，不填表示对未配置group的指定服务生效</li>
<li>version=1.0对指定服务的指定version生效，不填表示对未配置version的指定服务生效</li>
<li>category=routers 表示该数据为动态配置类型，必填。</li>
<li>dynamic=false 表示该数据为持久数据，当注册方退出时，数据依然保存在注册中心，必填。</li>
<li>enabled=true 覆盖规则是否生效，可不填，缺省生效。</li>
<li>force=false 当路由结果为空时，是否强制执行，如果不强制执行，路由结果为空的路由规则将自动失效，可不填，缺省为 false。</li>
<li>runtime=false 是否在每次调用时执行路由规则，否则只在提供者地址列表变更时预先执行并缓存结果，调用时直接从缓存中获取路由结果。如果用了参数路由，必须设为 true，需要注意设置会影响调用的性能，可不填，缺省为 false。</li>
<li>priority=1 路由规则的优先级，用于排序，优先级越大越靠前执行，可不填，缺省为 0。</li>
<li>rule=URL.encode(“host = 10.20.153.10 =&gt; host = 10.20.153.11”) 表示路由规则的内容，必填。</li>
</ul>
<h3 id="条件路由规则"><a href="#条件路由规则" class="headerlink" title="条件路由规则"></a>条件路由规则</h3><p>基于条件表达式的路由规则，如：host = 10.20.153.10 =&gt; host = 10.20.153.11</p>
<p>规则解释：</p>
<ul>
<li>=&gt; 之前的为消费者匹配条件，所有参数和消费者的 URL 进行对比，当消费者满足匹配条件时，对该消费者执行后面的过滤规则。</li>
<li>=&gt; 之后为提供者地址列表的过滤条件，所有参数和提供者的 URL 进行对比，消费者最终只拿到过滤后的地址列表。</li>
<li>如果匹配条件为空，表示对所有消费方应用，如：=&gt; host != 10.20.153.11</li>
<li>如果过滤条件为空，表示禁止访问，如：host = 10.20.153.10 =&gt;</li>
</ul>
<h3 id="表达式规则："><a href="#表达式规则：" class="headerlink" title="表达式规则："></a>表达式规则：</h3><blockquote>
<p>参数支持：</p>
</blockquote>
<ul>
<li>服务调用信息，如：method, argument 等，暂不支持参数路由</li>
<li>URL 本身的字段，如：protocol, host, port 等</li>
<li>以及 URL 上的所有参数，如：application, organization 等</li>
</ul>
<blockquote>
<p>条件支持：</p>
</blockquote>
<ul>
<li>等号 = 表示”匹配”，如：host = 10.20.153.10</li>
<li>不等号 != 表示”不匹配”，如：host != 10.20.153.10</li>
</ul>
<blockquote>
<p>值支持：</p>
</blockquote>
<ul>
<li>以逗号 , 分隔多个值，如：host != 10.20.153.10,10.20.153.11</li>
<li>以星号 <em> 结尾，表示通配，如：host != 10.20.</em></li>
<li>以美元符 $ 开头，表示引用消费者参数，如：host = $host</li>
</ul>
<blockquote>
<p>示例：</p>
</blockquote>
<p>排除预发布机：</p>
<ul>
<li>=&gt; host != 172.22.3.91</li>
</ul>
<blockquote>
<p>白名单：</p>
</blockquote>
<ul>
<li>host != 10.20.153.10,10.20.153.11 =&gt;</li>
</ul>
<blockquote>
<p>黑名单：</p>
</blockquote>
<ul>
<li>host = 10.20.153.10,10.20.153.11 =&gt;</li>
</ul>
<blockquote>
<p>服务寄宿在应用上，只暴露一部分的机器，防止整个集群挂掉：</p>
</blockquote>
<ul>
<li>=&gt; host = 172.22.3.1<em>,172.22.3.2</em></li>
</ul>
<blockquote>
<p>为重要应用提供额外的机器：</p>
</blockquote>
<ul>
<li>application != kylin =&gt; host != 172.22.3.95,172.22.3.96</li>
</ul>
<blockquote>
<p>读写分离：</p>
</blockquote>
<ul>
<li>method = find<em>,list</em>,get<em>,is</em> =&gt; host = 172.22.3.94,172.22.3.95,172.22.3.96</li>
<li>method != find<em>,list</em>,get<em>,is</em> =&gt; host = 172.22.3.97,172.22.3.98</li>
</ul>
<blockquote>
<p>前后台分离：</p>
</blockquote>
<ul>
<li>application = bops =&gt; host = 172.22.3.91,172.22.3.92,172.22.3.93</li>
<li>application != bops =&gt; host = 172.22.3.94,172.22.3.95,172.22.3.96</li>
</ul>
<blockquote>
<p>隔离不同机房网段：</p>
</blockquote>
<ul>
<li>host != 172.22.3.<em> =&gt; host != 172.22.3.</em></li>
</ul>
<blockquote>
<p>提供者与消费者部署在同集群内，本机只访问本机的服务：</p>
</blockquote>
<ul>
<li>=&gt; host = $host</li>
</ul>
<h4 id="脚本路由规则"><a href="#脚本路由规则" class="headerlink" title="脚本路由规则"></a>脚本路由规则</h4><p>脚本路由规则支持 JDK 脚本引擎的所有脚本，比如：javascript, jruby, groovy 等，通过 type=javascript 参数设置脚本类型，缺省为 javascript。</p>
<p>“script://0.0.0.0/com.foo.BarService?category=routers&amp;dynamic=false&amp;rule=” + URL.encode(“（function route(invokers) { … } (invokers)）”)</p>
<p>基于脚本引擎的路由规则，如：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">（<span class="function">function <span class="title">route</span><span class="params">(invokers)</span> </span>&#123;</span><br><span class="line">    var result = <span class="keyword">new</span> java.util.ArrayList(invokers.size());</span><br><span class="line">    <span class="keyword">for</span> (i = <span class="number">0</span>; i &lt; invokers.size(); i ++) &#123;</span><br><span class="line">        <span class="keyword">if</span> (<span class="string">"10.20.153.10"</span>.equals(invokers.get(i).getUrl().getHost())) &#123;</span><br><span class="line">            result.add(invokers.get(i));</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> result;</span><br><span class="line">&#125; (invokers)）; <span class="comment">// 表示立即执行方法</span></span><br></pre></td></tr></table></figure></p>
<ul>
<li>路由规则扩展点：路由扩展 </li>
<li>注意：一个服务只能有一条白名单规则，否则两条规则交叉，就都被筛选掉了</li>
<li>注意：脚本没有沙箱约束，可执行任意代码，存在后门风险 </li>
</ul>

          
        
      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </div>
  
  
  
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/2018/10/09/dubbo学习和使用（三）dubbo功能（1）/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="kyssion">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="kyssion-blog">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
                
                <a class="post-title-link" href="/2018/10/09/dubbo学习和使用（三）dubbo功能（1）/" itemprop="url">未命名</a></h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2018-10-09T15:22:37+08:00">
                2018-10-09
              </time>
            

            

            
          </span>

          

          
            
          

          
          

          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <h2 id="启动时检查"><a href="#启动时检查" class="headerlink" title="启动时检查"></a>启动时检查</h2><p>Dubbo 缺省会在启动时检查依赖的服务是否可用，不可用时会抛出异常，阻止 Spring 初始化完成，以便上线时，能及早发现问题，默认 check=”true”。</p>
<p>注意使用懒加载的时候可以指定这个方法为false，当这个为false的时候，如果服务不可用将会为null 而不是抛出异常，当服务恢复时，能自动连上。</p>
<h3 id="配置方法"><a href="#配置方法" class="headerlink" title="配置方法"></a>配置方法</h3><p>通过 spring 配置文件<br>关闭某个服务的启动时检查 (没有提供者时报错)：<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:reference</span> <span class="attr">interface</span>=<span class="string">"com.foo.BarService"</span> <span class="attr">check</span>=<span class="string">"false"</span> /&gt;</span></span><br></pre></td></tr></table></figure></p>
<p>关闭所有服务的启动时检查 (没有提供者时报错)：<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:consumer</span> <span class="attr">check</span>=<span class="string">"false"</span> /&gt;</span></span><br></pre></td></tr></table></figure></p>
<p>关闭注册中心启动时检查 (注册订阅失败时报错)：<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:registry</span> <span class="attr">check</span>=<span class="string">"false"</span> /&gt;</span></span><br></pre></td></tr></table></figure></p>
<p>通过 dubbo.properties<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">dubbo.reference.com.foo.BarService.check=false</span><br><span class="line">dubbo.reference.check=false</span><br><span class="line">dubbo.consumer.check=false</span><br><span class="line">dubbo.registry.check=false</span><br></pre></td></tr></table></figure></p>
<p>配置的含义</p>
<ul>
<li><p>dubbo.reference.check=false，强制改变所有 reference 的 check 值，就算配置中有声明，也会被覆盖。</p>
</li>
<li><p>dubbo.consumer.check=false，是设置 check 的缺省值，如果配置中有显式的声明，如：&lt;dubbo:reference check=”true”/&gt;，不会受影响。</p>
</li>
<li><p>dubbo.registry.check=false，前面两个都是指订阅成功，但提供者列表是否为空是否报错，如果注册订阅失败时，也允许启动，需使用此选项，将在后台定时重试。</p>
</li>
</ul>
<h2 id="集群容错"><a href="#集群容错" class="headerlink" title="集群容错"></a>集群容错</h2><p><img src="blogimg/dubbo/n4.png" alt=""></p>
<p>各节点关系：</p>
<ul>
<li>这里的 Invoker 是 Provider 的一个可调用 Service 的抽象，Invoker 封装了 Provider 地址及 Service 接口信息</li>
<li>Directory 代表多个 Invoker，可以把它看成 List<invoker> ，但与 List 不同的是，它的值可能是动态变化的，比如注册中心推送变更</invoker></li>
<li>Cluster 将 Directory 中的多个 Invoker 伪装成一个 Invoker，对上层透明，伪装过程包含了容错逻辑，调用失败后，重试另一个</li>
<li>Router 负责从多个 Invoker 中按路由规则选出子集，比如读写分离，应用隔离等</li>
<li>LoadBalance 负责从多个 Invoker 中选出具体的一个用于本次调用，选的过程包含了负载均衡算法，调用失败后，需要重选</li>
</ul>
<h3 id="集群容错模式"><a href="#集群容错模式" class="headerlink" title="集群容错模式"></a>集群容错模式</h3><blockquote>
<p>Failover Cluster</p>
</blockquote>
<p>失败自动切换，当出现失败，重试其它服务器 [1]。通常用于读操作，但重试会带来更长延迟。可通过 retries=”2” 来设置重试次数(不含第一次)。</p>
<p>重试次数配置如下：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:service</span> <span class="attr">retries</span>=<span class="string">"2"</span> /&gt;</span></span><br><span class="line">或</span><br><span class="line"><span class="tag">&lt;<span class="name">dubbo:reference</span> <span class="attr">retries</span>=<span class="string">"2"</span> /&gt;</span></span><br><span class="line">或</span><br><span class="line"><span class="tag">&lt;<span class="name">dubbo:reference</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dubbo:method</span> <span class="attr">name</span>=<span class="string">"findFoo"</span> <span class="attr">retries</span>=<span class="string">"2"</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dubbo:reference</span>&gt;</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>Failfast Cluster<br>快速失败，只发起一次调用，失败立即报错。通常用于非幂等性的写操作，比如新增记录。</p>
</blockquote>
<blockquote>
<p>Failsafe Cluster<br>失败安全，出现异常时，直接忽略。通常用于写入审计日志等操作。</p>
</blockquote>
<blockquote>
<p>Failback Cluster<br>失败自动恢复，后台记录失败请求，定时重发。通常用于消息通知操作。</p>
</blockquote>
<blockquote>
<p>Forking Cluster<br>并行调用多个服务器，只要一个成功即返回。通常用于实时性要求较高的读操作，但需要浪费更多服务资源。可通过 forks=”2” 来设置最大并行数。</p>
</blockquote>
<blockquote>
<p>Broadcast Cluster<br>广播调用所有提供者，逐个调用，任意一台报错则报错 [2]。通常用于通知所有提供者更新缓存或日志等本地资源信息。</p>
</blockquote>
<h3 id="集群模式配置"><a href="#集群模式配置" class="headerlink" title="集群模式配置"></a>集群模式配置</h3><p>按照以下示例在服务提供方和消费方配置集群模式</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:service</span> <span class="attr">cluster</span>=<span class="string">"failsafe"</span> /&gt;</span></span><br><span class="line">或</span><br><span class="line"><span class="tag">&lt;<span class="name">dubbo:reference</span> <span class="attr">cluster</span>=<span class="string">"failsafe"</span> /&gt;</span></span><br></pre></td></tr></table></figure>
<h2 id="负载均衡"><a href="#负载均衡" class="headerlink" title="负载均衡"></a>负载均衡</h2><p>在集群负载均衡时，Dubbo 提供了多种均衡策略，缺省为 random 随机调用。</p>
<h3 id="负载均衡策略"><a href="#负载均衡策略" class="headerlink" title="负载均衡策略"></a>负载均衡策略</h3><blockquote>
<p>Random LoadBalance</p>
</blockquote>
<p>随机，按权重设置随机概率。<br>在一个截面上碰撞的概率高，但调用量越大分布越均匀，而且按概率使用权重后也比较均匀，有利于动态调整提供者权重。</p>
<blockquote>
<p>RoundRobin LoadBalance</p>
</blockquote>
<p>轮循，按公约后的权重设置轮循比率。<br>存在慢的提供者累积请求的问题，比如：第二台机器很慢，但没挂，当请求调到第二台时就卡在那，久而久之，所有请求都卡在调到第二台上。</p>
<blockquote>
<p>LeastActive LoadBalance</p>
</blockquote>
<p>最少活跃调用数，相同活跃数的随机，活跃数指调用前后计数差。<br>使慢的提供者收到更少请求，因为越慢的提供者的调用前后计数差会越大。</p>
<blockquote>
<p>ConsistentHash LoadBalance<br>一致性 Hash，相同参数的请求总是发到同一提供者。<br>当某一台提供者挂时，原本发往该提供者的请求，基于虚拟节点，平摊到其它提供者，不会引起剧烈变动。<br>算法参见：<a href="http://en.wikipedia.org/wiki/Consistent_hashing" target="_blank" rel="noopener">http://en.wikipedia.org/wiki/Consistent_hashing</a><br>缺省只对第一个参数 Hash，如果要修改，请配置 </p>
</blockquote>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:parameter</span> <span class="attr">key</span>=<span class="string">"hash.arguments"</span> <span class="attr">value</span>=<span class="string">"0,1"</span> /&gt;</span></span><br></pre></td></tr></table></figure>
<p>缺省用 160 份虚拟节点，如果要修改，请配置<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:parameter</span> <span class="attr">key</span>=<span class="string">"hash.nodes"</span> <span class="attr">value</span>=<span class="string">"320"</span> /&gt;</span></span><br></pre></td></tr></table></figure></p>
<h3 id="配置"><a href="#配置" class="headerlink" title="配置"></a>配置</h3><p>服务端服务级别</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:service</span> <span class="attr">interface</span>=<span class="string">"..."</span> <span class="attr">loadbalance</span>=<span class="string">"roundrobin"</span> /&gt;</span></span><br></pre></td></tr></table></figure>
<p>客户端服务级别</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:reference</span> <span class="attr">interface</span>=<span class="string">"..."</span> <span class="attr">loadbalance</span>=<span class="string">"roundrobin"</span> /&gt;</span></span><br></pre></td></tr></table></figure>
<p>服务端方法级别</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:service</span> <span class="attr">interface</span>=<span class="string">"..."</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dubbo:method</span> <span class="attr">name</span>=<span class="string">"..."</span> <span class="attr">loadbalance</span>=<span class="string">"roundrobin"</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dubbo:service</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>客户端方法级别</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:reference</span> <span class="attr">interface</span>=<span class="string">"..."</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dubbo:method</span> <span class="attr">name</span>=<span class="string">"..."</span> <span class="attr">loadbalance</span>=<span class="string">"roundrobin"</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dubbo:reference</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h2 id="线程模型"><a href="#线程模型" class="headerlink" title="线程模型"></a>线程模型</h2><p>如果事件处理的逻辑能迅速完成，并且不会发起新的 IO 请求，比如只是在内存中记个标识，则直接在 IO 线程上处理更快，因为减少了线程池调度。</p>
<p>但如果事件处理逻辑较慢，或者需要发起新的 IO 请求，比如需要查询数据库，则必须派发到线程池，否则 IO 线程阻塞，将导致不能接收其它请求。</p>
<p>如果用 IO 线程处理事件，又在事件处理过程中发起新的 IO 请求，比如在连接事件中发起登录请求，会报“可能引发死锁”异常，但不会真死锁。</p>
<p><img src="blogimg/dubbo/n5.png" alt=""></p>
<p>因此，需要通过不同的派发策略和不同的线程池配置的组合来应对不同的场景:</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:protocol</span> <span class="attr">name</span>=<span class="string">"dubbo"</span> <span class="attr">dispatcher</span>=<span class="string">"all"</span> <span class="attr">threadpool</span>=<span class="string">"fixed"</span> <span class="attr">threads</span>=<span class="string">"100"</span> /&gt;</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>Dispatcher</p>
</blockquote>
<ul>
<li>all 所有消息都派发到线程池，包括请求，响应，连接事件，断开事件，心跳等。</li>
<li>direct 所有消息都不派发到线程池，全部在 IO 线程上直接执行。</li>
<li>message 只有请求响应消息派发到线程池，其它连接断开事件，心跳等消息，直接在 IO 线程上执行。</li>
<li>execution 只请求消息派发到线程池，不含响应，响应和其它连接断开事件，心跳等消息，直接在 IO 线程上执行。</li>
<li>connection 在 IO 线程上，将连接断开事件放入队列，有序逐个执行，其它消息派发到线程池。</li>
</ul>
<blockquote>
<p>ThreadPool</p>
</blockquote>
<ul>
<li>fixed 固定大小线程池，启动时建立线程，不关闭，一直持有。(缺省)</li>
<li>cached 缓存线程池，空闲一分钟自动删除，需要时重建。</li>
<li>limited 可伸缩线程池，但池中的线程数只会增长不会收缩。只增长不收缩的目的是为了避免收缩时突然来了大流量引起的性能问题。</li>
<li>eager 优先创建Worker线程池。在任务数量大于corePoolSize但是小于maximumPoolSize时，优先创建Worker来处理任务。当任务数量大于maximumPoolSize时，将任务放入阻塞队列中。阻塞队列充满时抛出RejectedExecutionException。(相比于cached:cached在任务数量超过maximumPoolSize时直接抛出异常而不是将任务放入阻塞队列)</li>
</ul>
<h2 id="直连提供者（只有测试环境使用）和只订阅，只注册"><a href="#直连提供者（只有测试环境使用）和只订阅，只注册" class="headerlink" title="直连提供者（只有测试环境使用）和只订阅，只注册"></a>直连提供者（只有测试环境使用）和只订阅，只注册</h2><h3 id="直连"><a href="#直连" class="headerlink" title="直连"></a>直连</h3><p>在开发及测试环境下，经常需要绕过注册中心，只测试指定服务提供者，这时候可能需要点对点直连，点对点直联方式，将以服务接口为单位，<strong>忽略注册中心的提供者列表</strong>，A 接口配置点对点，不影响 B 接口从注册中心获取列表。</p>
<blockquote>
<p>通过 XML 配置</p>
</blockquote>
<p>如果是线上需求需要点对点，可在 <a href="dubbo:reference" target="_blank" rel="noopener">dubbo:reference</a> 中配置 url 指向提供者，将绕过注册中心，多个地址用分号隔开，配置如下 [1]：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:reference</span> <span class="attr">id</span>=<span class="string">"xxxService"</span> <span class="attr">interface</span>=<span class="string">"com.alibaba.xxx.XxxService"</span> <span class="attr">url</span>=<span class="string">"dubbo://localhost:20890"</span> /&gt;</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>通过文件映射</p>
</blockquote>
<p>如果服务比较多，也可以用文件映射，用 -Ddubbo.resolve.file 指定映射文件路径，此配置优先级高于 <a href="dubbo:reference" target="_blank" rel="noopener">dubbo:reference</a> 中的配置 [3]，如：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">java -Ddubbo.resolve.file=xxx.properties</span><br></pre></td></tr></table></figure>
<p>然后在映射文件 xxx.properties 中加入配置，其中 key 为服务名，value 为服务提供者 URL：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">com.alibaba.xxx.XxxService=dubbo://localhost:20890</span><br></pre></td></tr></table></figure>
<blockquote>
<p>注意:为了避免复杂化线上环境，不要在线上使用这个功能，只应在测试阶段使用。</p>
</blockquote>
<h3 id="禁用注册"><a href="#禁用注册" class="headerlink" title="禁用注册"></a>禁用注册</h3><p>就是指服务方可以拉取配置中心的信息当时并不在配置中心进行注册</p>
<p><img src="blogimg/dubbo/n6.png" alt=""></p>
<p>禁用注册配置<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:registry</span> <span class="attr">address</span>=<span class="string">"10.20.153.10:9090"</span> <span class="attr">register</span>=<span class="string">"false"</span> /&gt;</span></span><br></pre></td></tr></table></figure></p>
<p>或者<br><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:registry</span> <span class="attr">address</span>=<span class="string">"10.20.153.10:9090?register=false"</span> /&gt;</span></span><br></pre></td></tr></table></figure></p>
<h3 id="禁用拉取"><a href="#禁用拉取" class="headerlink" title="禁用拉取"></a>禁用拉取</h3><p>制定一个配置中心只将自己注册进去但是不进行订阅功能</p>
<p>禁用订阅配置</p>
<p>&lt;dubbo:registry id=”hzRegistry” address=”10.20.153.10:9090” /&gt;<br>&lt;dubbo:registry id=”qdRegistry” address=”10.20.141.150:9090” subscribe=”false” /&gt;<br>或者</p>
<p>&lt;dubbo:registry id=”hzRegistry” address=”10.20.153.10:9090” /&gt;<br>&lt;dubbo:registry id=”qdRegistry” address=”10.20.141.150:9090?subscribe=false” /&gt;</p>
<h2 id="多协议"><a href="#多协议" class="headerlink" title="多协议"></a>多协议</h2><blockquote>
<p>不同服务不同协议</p>
</blockquote>
<p>不同服务在性能上适用不同协议进行传输，比如大数据用短连接协议，小数据大并发用长连接协议</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span><br><span class="line"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">"http://www.springframework.org/schema/beans"</span></span></span><br><span class="line"><span class="tag">    <span class="attr">xmlns:xsi</span>=<span class="string">"http://www.w3.org/2001/XMLSchema-instance"</span></span></span><br><span class="line"><span class="tag">    <span class="attr">xmlns:dubbo</span>=<span class="string">"http://dubbo.apache.org/schema/dubbo"</span></span></span><br><span class="line"><span class="tag">    <span class="attr">xsi:schemaLocation</span>=<span class="string">"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd"</span>&gt;</span> </span><br><span class="line">    <span class="tag">&lt;<span class="name">dubbo:application</span> <span class="attr">name</span>=<span class="string">"world"</span>  /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dubbo:registry</span> <span class="attr">id</span>=<span class="string">"registry"</span> <span class="attr">address</span>=<span class="string">"10.20.141.150:9090"</span> <span class="attr">username</span>=<span class="string">"admin"</span> <span class="attr">password</span>=<span class="string">"hello1234"</span> /&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- 多协议配置 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dubbo:protocol</span> <span class="attr">name</span>=<span class="string">"dubbo"</span> <span class="attr">port</span>=<span class="string">"20880"</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dubbo:protocol</span> <span class="attr">name</span>=<span class="string">"rmi"</span> <span class="attr">port</span>=<span class="string">"1099"</span> /&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- 使用dubbo协议暴露服务 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dubbo:service</span> <span class="attr">interface</span>=<span class="string">"com.alibaba.hello.api.HelloService"</span> <span class="attr">version</span>=<span class="string">"1.0.0"</span> <span class="attr">ref</span>=<span class="string">"helloService"</span> <span class="attr">protocol</span>=<span class="string">"dubbo"</span> /&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- 使用rmi协议暴露服务 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dubbo:service</span> <span class="attr">interface</span>=<span class="string">"com.alibaba.hello.api.DemoService"</span> <span class="attr">version</span>=<span class="string">"1.0.0"</span> <span class="attr">ref</span>=<span class="string">"demoService"</span> <span class="attr">protocol</span>=<span class="string">"rmi"</span> /&gt;</span> </span><br><span class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>多协议暴露服务</p>
</blockquote>
<p>需要与 http 客户端互操作</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span><br><span class="line"><span class="tag">&lt;<span class="name">beans</span> <span class="attr">xmlns</span>=<span class="string">"http://www.springframework.org/schema/beans"</span></span></span><br><span class="line"><span class="tag">    <span class="attr">xmlns:xsi</span>=<span class="string">"http://www.w3.org/2001/XMLSchema-instance"</span></span></span><br><span class="line"><span class="tag">    <span class="attr">xmlns:dubbo</span>=<span class="string">"http://dubbo.apache.org/schema/dubbo"</span></span></span><br><span class="line"><span class="tag">    <span class="attr">xsi:schemaLocation</span>=<span class="string">"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dubbo:application</span> <span class="attr">name</span>=<span class="string">"world"</span>  /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dubbo:registry</span> <span class="attr">id</span>=<span class="string">"registry"</span> <span class="attr">address</span>=<span class="string">"10.20.141.150:9090"</span> <span class="attr">username</span>=<span class="string">"admin"</span> <span class="attr">password</span>=<span class="string">"hello1234"</span> /&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- 多协议配置 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dubbo:protocol</span> <span class="attr">name</span>=<span class="string">"dubbo"</span> <span class="attr">port</span>=<span class="string">"20880"</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dubbo:protocol</span> <span class="attr">name</span>=<span class="string">"hessian"</span> <span class="attr">port</span>=<span class="string">"8080"</span> /&gt;</span></span><br><span class="line">    <span class="comment">&lt;!-- 使用多个协议暴露服务 --&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dubbo:service</span> <span class="attr">id</span>=<span class="string">"helloService"</span> <span class="attr">interface</span>=<span class="string">"com.alibaba.hello.api.HelloService"</span> <span class="attr">version</span>=<span class="string">"1.0.0"</span> <span class="attr">protocol</span>=<span class="string">"dubbo,hessian"</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h2 id="服务分组"><a href="#服务分组" class="headerlink" title="服务分组"></a>服务分组</h2><p>当一个接口有多种实现时，可以用 group 区分。</p>
<blockquote>
<p>服务</p>
</blockquote>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:service</span> <span class="attr">group</span>=<span class="string">"feedback"</span> <span class="attr">interface</span>=<span class="string">"com.xxx.IndexService"</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dubbo:service</span> <span class="attr">group</span>=<span class="string">"member"</span> <span class="attr">interface</span>=<span class="string">"com.xxx.IndexService"</span> /&gt;</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>引用</p>
</blockquote>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:reference</span> <span class="attr">id</span>=<span class="string">"feedbackIndexService"</span> <span class="attr">group</span>=<span class="string">"feedback"</span> <span class="attr">interface</span>=<span class="string">"com.xxx.IndexService"</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">dubbo:reference</span> <span class="attr">id</span>=<span class="string">"memberIndexService"</span> <span class="attr">group</span>=<span class="string">"member"</span> <span class="attr">interface</span>=<span class="string">"com.xxx.IndexService"</span> /&gt;</span></span><br><span class="line"></span><br><span class="line">&gt; 任意组</span><br><span class="line"></span><br><span class="line">```xml</span><br><span class="line"><span class="tag">&lt;<span class="name">dubbo:reference</span> <span class="attr">id</span>=<span class="string">"barService"</span> <span class="attr">interface</span>=<span class="string">"com.foo.BarService"</span> <span class="attr">group</span>=<span class="string">"*"</span> /&gt;</span></span><br></pre></td></tr></table></figure>
<h2 id="多版本"><a href="#多版本" class="headerlink" title="多版本"></a>多版本</h2><p>当一个接口实现，出现不兼容升级时，可以用版本号过渡，版本号不同的服务相互间不引用。</p>
<p>可以按照以下的步骤进行版本迁移：</p>
<ul>
<li>在低压力时间段，先升级一半提供者为新版本</li>
<li>再将所有消费者升级为新版本</li>
<li>然后将剩下的一半提供者升级为新版本</li>
</ul>
<blockquote>
<p>老版本服务提供者配置：</p>
</blockquote>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:service</span> <span class="attr">interface</span>=<span class="string">"com.foo.BarService"</span> <span class="attr">version</span>=<span class="string">"1.0.0"</span> /&gt;</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>新版本服务提供者配置：</p>
</blockquote>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:service</span> <span class="attr">interface</span>=<span class="string">"com.foo.BarService"</span> <span class="attr">version</span>=<span class="string">"2.0.0"</span> /&gt;</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>老版本服务消费者配置：</p>
</blockquote>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:reference</span> <span class="attr">id</span>=<span class="string">"barService"</span> <span class="attr">interface</span>=<span class="string">"com.foo.BarService"</span> <span class="attr">version</span>=<span class="string">"1.0.0"</span> /&gt;</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>新版本服务消费者配置：</p>
</blockquote>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:reference</span> <span class="attr">id</span>=<span class="string">"barService"</span> <span class="attr">interface</span>=<span class="string">"com.foo.BarService"</span> <span class="attr">version</span>=<span class="string">"2.0.0"</span> /&gt;</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>如果不需要区分版本，可以按照以下的方式配置 [1]：</p>
</blockquote>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:reference</span> <span class="attr">id</span>=<span class="string">"barService"</span> <span class="attr">interface</span>=<span class="string">"com.foo.BarService"</span> <span class="attr">version</span>=<span class="string">"*"</span> /&gt;</span></span><br></pre></td></tr></table></figure>
<h2 id="分组聚合"><a href="#分组聚合" class="headerlink" title="分组聚合"></a>分组聚合</h2><p>按组合并返回结果 [1]，比如菜单服务，接口一样，但有多种实现，用group区分，现在消费方需从每种<strong>group</strong>中调用一次返回结果，合并结果返回，这样就可以实现聚合菜单项。</p>
<blockquote>
<p>配置</p>
</blockquote>
<p>搜索所有分组</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:reference</span> <span class="attr">interface</span>=<span class="string">"com.xxx.MenuService"</span> <span class="attr">group</span>=<span class="string">"*"</span> <span class="attr">merger</span>=<span class="string">"true"</span> /&gt;</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>合并指定分组</p>
</blockquote>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:reference</span> <span class="attr">interface</span>=<span class="string">"com.xxx.MenuService"</span> <span class="attr">group</span>=<span class="string">"aaa,bbb"</span> <span class="attr">merger</span>=<span class="string">"true"</span> /&gt;</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>指定方法合并结果，其它未指定的方法，将只调用一个 Group</p>
</blockquote>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:reference</span> <span class="attr">interface</span>=<span class="string">"com.xxx.MenuService"</span> <span class="attr">group</span>=<span class="string">"*"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dubbo:method</span> <span class="attr">name</span>=<span class="string">"getMenuItems"</span> <span class="attr">merger</span>=<span class="string">"true"</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dubbo:service</span>&gt;</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>某个方法不合并结果，其它都合并结果</p>
</blockquote>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:reference</span> <span class="attr">interface</span>=<span class="string">"com.xxx.MenuService"</span> <span class="attr">group</span>=<span class="string">"*"</span> <span class="attr">merger</span>=<span class="string">"true"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dubbo:method</span> <span class="attr">name</span>=<span class="string">"getMenuItems"</span> <span class="attr">merger</span>=<span class="string">"false"</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dubbo:service</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>指定合并策略，缺省根据返回值类型自动匹配，如果同一类型有两个合并器时，需指定合并器的名称</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:reference</span> <span class="attr">interface</span>=<span class="string">"com.xxx.MenuService"</span> <span class="attr">group</span>=<span class="string">"*"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dubbo:method</span> <span class="attr">name</span>=<span class="string">"getMenuItems"</span> <span class="attr">merger</span>=<span class="string">"mymerge"</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dubbo:service</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>指定合并方法，将调用返回结果的指定方法进行合并，合并方法的参数类型必须是返回结果类型本身</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:reference</span> <span class="attr">interface</span>=<span class="string">"com.xxx.MenuService"</span> <span class="attr">group</span>=<span class="string">"*"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dubbo:method</span> <span class="attr">name</span>=<span class="string">"getMenuItems"</span> <span class="attr">merger</span>=<span class="string">".addAll"</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dubbo:service</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h2 id="结果缓存"><a href="#结果缓存" class="headerlink" title="结果缓存"></a>结果缓存</h2><p>结果缓存 [1]，用于加速热门数据的访问速度，Dubbo 提供声明式缓存，以减少用户加缓存的工作量 [2]。</p>
<blockquote>
<p>缓存类型</p>
</blockquote>
<ul>
<li>lru 基于最近最少使用原则删除多余缓存，保持最热的数据被缓存。</li>
<li>threadlocal 当前线程缓存，比如一个页面渲染，用到很多 portal，每个 portal 都要去查用户信息，通过线程缓存，可以减少这种多余访问。</li>
<li>jcache 与 JSR107 集成，可以桥接各种缓存实现。</li>
<li>缓存类型可扩展，参见：缓存扩展</li>
</ul>
<blockquote>
<p>配置</p>
</blockquote>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:reference</span> <span class="attr">interface</span>=<span class="string">"com.foo.BarService"</span> <span class="attr">cache</span>=<span class="string">"lru"</span> /&gt;</span></span><br></pre></td></tr></table></figure>
<p>或：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:reference</span> <span class="attr">interface</span>=<span class="string">"com.foo.BarService"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dubbo:method</span> <span class="attr">name</span>=<span class="string">"findBar"</span> <span class="attr">cache</span>=<span class="string">"lru"</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dubbo:reference</span>&gt;</span></span><br></pre></td></tr></table></figure>
<h2 id="使用泛化调用"><a href="#使用泛化调用" class="headerlink" title="使用泛化调用"></a>使用泛化调用</h2><p>泛化接口调用方式主要用于客户端没有 API 接口及模型类元的情况，参数及返回值中的所有 POJO 均用 Map 表示，通常用于框架集成，比如：实现一个通用的服务测试框架，可通过 GenericService 调用所有服务实现。</p>
<p>通过 Spring 使用泛化调用<br>在 Spring 配置申明 generic=”true”：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:reference</span> <span class="attr">id</span>=<span class="string">"barService"</span> <span class="attr">interface</span>=<span class="string">"com.foo.BarService"</span> <span class="attr">generic</span>=<span class="string">"true"</span> /&gt;</span></span><br></pre></td></tr></table></figure>
<p>在 Java 代码获取 barService 并开始泛化调用：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">GenericService barService = (GenericService) applicationContext.getBean(<span class="string">"barService"</span>);</span><br><span class="line">Object result = barService.$invoke(<span class="string">"sayHello"</span>, <span class="keyword">new</span> String[] &#123; <span class="string">"java.lang.String"</span> &#125;, <span class="keyword">new</span> Object[] &#123; <span class="string">"World"</span> &#125;);</span><br></pre></td></tr></table></figure>
<blockquote>
<p>通过 API 方式使用泛化调用</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> com.alibaba.dubbo.rpc.service.GenericService; </span><br><span class="line">... </span><br><span class="line"> </span><br><span class="line"><span class="comment">// 引用远程服务 </span></span><br><span class="line"><span class="comment">// 该实例很重量，里面封装了所有与注册中心及服务提供方连接，请缓存</span></span><br><span class="line">ReferenceConfig&lt;GenericService&gt; reference = <span class="keyword">new</span> ReferenceConfig&lt;GenericService&gt;(); </span><br><span class="line"><span class="comment">// 弱类型接口名</span></span><br><span class="line">reference.setInterface(<span class="string">"com.xxx.XxxService"</span>);  </span><br><span class="line">reference.setVersion(<span class="string">"1.0.0"</span>);</span><br><span class="line"><span class="comment">// 声明为泛化接口 </span></span><br><span class="line">reference.setGeneric(<span class="keyword">true</span>);  </span><br><span class="line"></span><br><span class="line"><span class="comment">// 用com.alibaba.dubbo.rpc.service.GenericService可以替代所有接口引用  </span></span><br><span class="line">GenericService genericService = reference.get(); </span><br><span class="line"> </span><br><span class="line"><span class="comment">// 基本类型以及Date,List,Map等不需要转换，直接调用 </span></span><br><span class="line">Object result = genericService.$invoke(<span class="string">"sayHello"</span>, <span class="keyword">new</span> String[] &#123;<span class="string">"java.lang.String"</span>&#125;, <span class="keyword">new</span> Object[] &#123;<span class="string">"world"</span>&#125;); </span><br><span class="line"> </span><br><span class="line"><span class="comment">// 用Map表示POJO参数，如果返回值为POJO也将自动转成Map </span></span><br><span class="line">Map&lt;String, Object&gt; person = <span class="keyword">new</span> HashMap&lt;String, Object&gt;(); </span><br><span class="line">person.put(<span class="string">"name"</span>, <span class="string">"xxx"</span>); </span><br><span class="line">person.put(<span class="string">"password"</span>, <span class="string">"yyy"</span>); </span><br><span class="line"><span class="comment">// 如果返回POJO将自动转成Map </span></span><br><span class="line">Object result = genericService.$invoke(<span class="string">"findPerson"</span>, <span class="keyword">new</span> String[]</span><br><span class="line">&#123;<span class="string">"com.xxx.Person"</span>&#125;, <span class="keyword">new</span> Object[]&#123;person&#125;);</span><br></pre></td></tr></table></figure>
<blockquote>
<p>有关泛化类型的进一步解释</p>
</blockquote>
<p>假设存在 POJO 如：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.xxx;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">PersonImpl</span> <span class="keyword">implements</span> <span class="title">Person</span> </span>&#123;</span><br><span class="line">    <span class="keyword">private</span> String name;</span><br><span class="line">    <span class="keyword">private</span> String password;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">getName</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> name;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setName</span><span class="params">(String name)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.name = name;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> String <span class="title">getPassword</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> password;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setPassword</span><span class="params">(String password)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.password = password;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<blockquote>
<p>则 POJO 数据：</p>
</blockquote>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">Person person = <span class="keyword">new</span> PersonImpl(); </span><br><span class="line">person.setName(<span class="string">"xxx"</span>); </span><br><span class="line">person.setPassword(<span class="string">"yyy"</span>);</span><br></pre></td></tr></table></figure>
<p>可用下面 Map 表示：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">Map&lt;String, Object&gt; map = <span class="keyword">new</span> HashMap&lt;String, Object&gt;(); </span><br><span class="line"><span class="comment">// 注意：如果参数类型是接口，或者List等丢失泛型，可通过class属性指定类型。</span></span><br><span class="line">map.put(<span class="string">"class"</span>, <span class="string">"com.xxx.PersonImpl"</span>); </span><br><span class="line">map.put(<span class="string">"name"</span>, <span class="string">"xxx"</span>); </span><br><span class="line">map.put(<span class="string">"password"</span>, <span class="string">"yyy"</span>);</span><br></pre></td></tr></table></figure>
          
        
      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </div>
  
  
  
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/2018/10/09/docker（四）dockerfile指令/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="kyssion">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="kyssion-blog">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
                
                <a class="post-title-link" href="/2018/10/09/docker（四）dockerfile指令/" itemprop="url">未命名</a></h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2018-10-09T15:22:37+08:00">
                2018-10-09
              </time>
            

            

            
          </span>

          

          
            
          

          
          

          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <h3 id="COPY-复制文件"><a href="#COPY-复制文件" class="headerlink" title="COPY 复制文件"></a>COPY 复制文件</h3><p>格式：<br><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">COPY &lt;源路径&gt;... &lt;目标路径&gt;</span><br><span class="line">COPY ["&lt;源路径1&gt;",... "&lt;目标路径&gt;"]</span><br></pre></td></tr></table></figure></p>
<p>&lt;源路径&gt; 可以是多个，甚至可以是通配符，其通配符规则要满足 Go 的 filepath.Match 规则，如：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">COPY hom* /mydir/</span><br><span class="line">COPY hom?.txt /mydir/</span><br></pre></td></tr></table></figure>
<p>&lt;目标路径&gt; 可以是容器内的绝对路径，也可以是相对于工作目录的相对路径（工作目录可以用 WORKDIR 指令来指定）。目标路径不需要事先创建，如果目录不存在会在复制文件前先行创建缺失目录。</p>
<p>此外，还需要注意一点，使用 COPY 指令，源文件的各种元数据都会保留。比如读、写、执行权限、文件变更时间等。这个特性对于镜像定制很有用。特别是构建相关文件都在使用 Git 进行管理的时候。</p>
<h3 id="ADD-更高级的复制文件"><a href="#ADD-更高级的复制文件" class="headerlink" title="ADD 更高级的复制文件"></a>ADD 更高级的复制文件</h3><p>ADD 指令和 COPY 的格式和性质基本一致。但是在 COPY 基础上增加了一些功能。</p>
<p>比如 &lt;源路径&gt; 可以是一个 URL，这种情况下，Docker 引擎会试图去下载这个链接的文件放到 &lt;目标路径&gt; 去。下载后的文件权限自动设置为 600，如果这并不是想要的权限，那么还需要增加额外的一层 RUN 进行权限调整，另外，如果下载的是个压缩包，需要解压缩，也一样还需要额外的一层 RUN 指令进行解压缩。</p>
<blockquote>
<p>注意: 如果 &lt;源路径&gt; 为一个 tar 压缩文件的话，压缩格式为 gzip, bzip2 以及 xz 的情况下，ADD 指令将会自动解压缩这个压缩文件到 &lt;目标路径&gt; 去。</p>
</blockquote>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">FROM scratch</span><br><span class="line">ADD ubuntu-xenial-core-cloudimg-amd64-root.tar.gz /</span><br><span class="line">...</span><br></pre></td></tr></table></figure>
<p>在 Docker 官方的 Dockerfile 最佳实践文档 中要求，尽可能的使用 COPY，因为 COPY 的语义很明确，就是复制文件而已，而 ADD 则包含了更复杂的功能，其行为也不一定很清晰。最适合使用 ADD 的场合，就是所提及的需要自动解压缩的场合。</p>
<h3 id="CMD-容器启动命令"><a href="#CMD-容器启动命令" class="headerlink" title="CMD 容器启动命令"></a>CMD 容器启动命令</h3><p>CMD 指令的格式和 RUN 相似，也是两种格式：</p>
<ul>
<li>shell 格式：CMD &lt;命令&gt;</li>
<li>exec 格式：CMD [“可执行文件”, “参数1”, “参数2”…]</li>
<li>参数列表格式：CMD [“参数1”, “参数2”…]。在指定了 ENTRYPOINT 指令后，用 CMD 指定具体的参数。 之后使用docker run 的时候可以动态的添加命令到指定的数据中<br>之前介绍容器的时候曾经说过，Docker 不是虚拟机，容器就是进程。既然是进程，那么在启动容器的时候，需要指定所运行的程序及参数。CMD 指令就是用于指定默认的容器主进程的启动命令的。</li>
</ul>
<blockquote>
<p>注意： 在指令格式上，一般推荐使用 exec 格式，这类格式在解析时会被解析为 JSON 数组，因此一定要使用双引号 “，而不要使用单引号。</p>
</blockquote>
<p>如果使用 shell 格式的话，实际的命令会被包装为 sh -c 的参数的形式进行执行。比如：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">CMD echo $HOME</span><br></pre></td></tr></table></figure>
<p>在实际执行中，会将其变更为：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">CMD [ "sh", "-c", "echo $HOME" ]</span><br></pre></td></tr></table></figure>
<p>这就是为什么我们可以使用环境变量的原因，因为这些环境变量会被 shell 进行解析处理。</p>
<p>注意：Docker 不是虚拟机，容器中的应用都应该以前台执行，而不是像虚拟机、物理机里面那样，用 upstart/systemd 去启动后台服务，容器内没有后台服务的概念。</p>
<p>比如 使用 CMD service nginx start 容器执行后就立即退出</p>
<p>使用 service nginx start 命令，则是希望 upstart 来以后台守护进程形式启动 nginx 服务。而刚才说了 CMD service nginx start 会被理解为 CMD [ “sh”, “-c”, “service nginx start”]，因此主进程实际上是 sh。那么当 service nginx start 命令结束后，sh 也就结束了，sh 作为主进程退出了，自然就会令容器退出。</p>
<p>正确的做法是直接执行 nginx 可执行文件，并且要求以前台形式运行。比如：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">CMD ["nginx", "-g", "daemon off;"]</span><br></pre></td></tr></table></figure>
<p>注意： 如果 docker run 指定了其他命令，CMD 指定的默认命令将被忽略。如果 Dockerfile 中有多个 CMD 指令，只有最后一个 CMD 有效。</p>
<h3 id="ENTRYPOINT-入口点"><a href="#ENTRYPOINT-入口点" class="headerlink" title="ENTRYPOINT 入口点"></a>ENTRYPOINT 入口点</h3><p>这个方法相当于默认容器启动的时候运行的命令</p>
<p>ENTRYPOINT 的格式和 RUN 指令格式一样，分为 exec 格式和 shell 格式。</p>
<p>ENTRYPOINT 的目的和 CMD 一样，都是在指定容器启动程序及参数。ENTRYPOINT 在运行时也可以替代，不过比 CMD 要略显繁琐，需要通过 docker run 的参数 –entrypoint 来指定。</p>
<p>当指定了 ENTRYPOINT 后，CMD 的含义就发生了改变，不再是直接的运行其命令，而是将 CMD 的内容作为参数传给 ENTRYPOINT 指令，换句话说实际执行时，将变为：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;ENTRYPOINT&gt; "&lt;CMD&gt;"</span><br></pre></td></tr></table></figure>
<p>高级应用类似 redis 官方镜像，自定义启动效果</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">FROM alpine:3.4</span><br><span class="line">...</span><br><span class="line">RUN addgroup -S redis &amp;&amp; adduser -S -G redis redis</span><br><span class="line">...</span><br><span class="line">ENTRYPOINT ["docker-entrypoint.sh"]</span><br><span class="line"></span><br><span class="line">EXPOSE 6379</span><br><span class="line">CMD [ "redis-server" ]</span><br></pre></td></tr></table></figure>
<p>可以看到其中为了 redis 服务创建了 redis 用户，并在最后指定了 ENTRYPOINT 为 docker-entrypoint.sh 脚本。</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#</span><span class="bash">!/bin/sh</span></span><br><span class="line">...</span><br><span class="line"><span class="meta">#</span><span class="bash"> allow the container to be started with `--user`</span></span><br><span class="line">if [ "$1" = 'redis-server' -a "$(id -u)" = '0' ]; then</span><br><span class="line">    chown -R redis .</span><br><span class="line">    exec su-exec redis "$0" "$@"</span><br><span class="line">fi</span><br><span class="line"></span><br><span class="line">exec "$@"</span><br></pre></td></tr></table></figure>
<p>该脚本的内容就是根据 CMD 的内容来判断，如果是 redis-server 的话，则切换到 redis 用户身份启动服务器，否则依旧使用 root 身份执行。比如：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span><span class="bash"> docker run -it redis id</span></span><br><span class="line">uid=0(root) gid=0(root) groups=0(root)</span><br></pre></td></tr></table></figure>
<h3 id="RUN-vs-CMD-vs-ENTRYPOINT"><a href="#RUN-vs-CMD-vs-ENTRYPOINT" class="headerlink" title="RUN vs CMD vs ENTRYPOINT"></a>RUN vs CMD vs ENTRYPOINT</h3><p>RUN、CMD 和 ENTRYPOINT 这三个 Dockerfile 指令看上去很类似，很容易混淆。本节将通过实践详细讨论它们的区别。</p>
<p>简单的说：</p>
<ul>
<li><p>RUN 执行命令并创建新的镜像层，RUN 经常用于安装软件包。</p>
</li>
<li><p>CMD 设置容器启动后默认执行的命令及其参数，但 CMD 能够被 docker run 后面跟的命令行参数替换。</p>
</li>
<li><p>ENTRYPOINT 配置容器启动时运行的命令。</p>
</li>
</ul>
<p>最佳实践</p>
<ul>
<li><p>使用 RUN 指令安装应用和软件包，构建镜像。</p>
</li>
<li><p>如果 Docker 镜像的用途是运行应用程序或服务，比如运行一个 MySQL，应该优先使用 Exec 格式的 ENTRYPOINT 指令。CMD 可为 ENTRYPOINT 提供额外的默认参数，同时可利用 docker run 命令行替换默认参数。</p>
</li>
<li><p>如果想为容器设置默认的启动命令，可使用 CMD 指令。用户可在 docker run 命令行中替换此默认命令。</p>
</li>
</ul>
<h3 id="ENV-设置环境变量"><a href="#ENV-设置环境变量" class="headerlink" title="ENV 设置环境变量"></a>ENV 设置环境变量</h3><p>格式有两种：<br><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">- ENV &lt;key&gt; &lt;value&gt;</span><br><span class="line">- ENV &lt;key1&gt;=&lt;value1&gt; &lt;key2&gt;=&lt;value2&gt;...</span><br></pre></td></tr></table></figure></p>
<p>这个指令很简单，就是设置环境变量而已，无论是后面的其它指令，如 RUN，还是运行时的应用，都可以直接使用这里定义的环境变量。</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">ENV VERSION=1.0 DEBUG=on \</span><br><span class="line">    NAME="Happy Feet"</span><br></pre></td></tr></table></figure>
<p>除此之外还能使用环境变量在编写docker文件的时候进行使用，专业术语变量展开</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">ENV NODE_VERSION 7.2.0</span><br><span class="line"></span><br><span class="line">RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz" \</span><br><span class="line">  &amp;&amp; curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc" \</span><br><span class="line">  &amp;&amp; gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \</span><br><span class="line">  &amp;&amp; grep " node-v$NODE_VERSION-linux-x64.tar.xz\$" SHASUMS256.txt | sha256sum -c - \</span><br><span class="line">  &amp;&amp; tar -xJf "node-v$NODE_VERSION-linux-x64.tar.xz" -C /usr/local --strip-components=1 \</span><br><span class="line">  &amp;&amp; rm "node-v$NODE_VERSION-linux-x64.tar.xz" SHASUMS256.txt.asc SHASUMS256.txt \</span><br><span class="line">  &amp;&amp; ln -s /usr/local/bin/node /usr/local/bin/nodejs</span><br></pre></td></tr></table></figure>
<p>下列指令可以支持环境变量展开： ADD、COPY、ENV、EXPOSE、LABEL、USER、WORKDIR、VOLUME、STOPSIGNAL、ONBUILD。</p>
<p>可以从这个指令列表里感觉到，环境变量可以使用的地方很多，很强大。通过环境变量，我们可以让一份 Dockerfile 制作更多的镜像，只需使用不同的环境变量即可。</p>
<h3 id="ARG-设置环境变量"><a href="#ARG-设置环境变量" class="headerlink" title="ARG    设置环境变量"></a>ARG    设置环境变量</h3><p>构建参数和ENV的效果一样,都是设置环境变量。但是arg还可以将相关的变量使用进编译过程中</p>
<h3 id="VOLUME-定义匿名卷"><a href="#VOLUME-定义匿名卷" class="headerlink" title="VOLUME 定义匿名卷"></a>VOLUME 定义匿名卷</h3><p>格式为：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">VOLUME ["&lt;路径1&gt;", "&lt;路径2&gt;"...]</span><br><span class="line">VOLUME &lt;路径&gt;</span><br></pre></td></tr></table></figure>
<p>之前我们说过，容器运行时应该尽量保持容器存储层不发生写操作，对于数据库类需要保存动态数据的应用，其数据库文件应该保存于卷(volume)中，后面的章节我们会进一步介绍 Docker 卷的概念。</p>
<p>之前我们说过，容器运行时应该尽量保持容器存储层不发生写操作，对于数据库类需要保存动态数据的应用，其数据库文件应该保存于卷(volume)中</p>
<h3 id="EXPOSE-声明端口"><a href="#EXPOSE-声明端口" class="headerlink" title="EXPOSE 声明端口"></a>EXPOSE 声明端口</h3><p>格式为 EXPOSE &lt;端口1&gt; [&lt;端口2&gt;…]。</p>
<p>在 Dockerfile 中写入这样的声明有两个好处：</p>
<ul>
<li>帮助镜像使用者理解这个镜像服务的守护端口，以方便配置映射。</li>
<li>在运行时使用随机端口映射时，也就是 docker run -P 时，会自动随机映射 EXPOSE 的端口。</li>
</ul>
<p>早期 Docker 版本中还有一个特殊的用处，解决以前所有容器都运行于默认桥接网络中，所有容器互相之间都可以直接访问导致的安全性问题。</p>
<p>于是有了一个 Docker 引擎参数 –icc=false</p>
<blockquote>
<p>–icc=false参数作用：当指定该参数后，容器间将默认无法互访，除非互相间使用了 –links 参数的容器才可以互通，并且只有镜像中 EXPOSE 所声明的端口才可以被访问。这个 –icc=false 的用法，在引入了 docker network 后已经基本不用了，通过自定义网络可以很轻松的实现容器间的互联与隔离。</p>
</blockquote>
<p>注意：要将 EXPOSE 和在运行时使用 -p &lt;宿主端口&gt;:&lt;容器端口&gt; 区分开来。-p，是映射宿主端口和容器端口，换句话说，就是将容器的对应端口服务公开给外界访问，而 EXPOSE 仅仅是声明容器打算使用什么端口而已，并不会自动在宿主进行端口映射。</p>
<h3 id="WORKDIR-指定工作目录"><a href="#WORKDIR-指定工作目录" class="headerlink" title="WORKDIR 指定工作目录"></a>WORKDIR 指定工作目录</h3><p>格式为 WORKDIR &lt;工作目录路径&gt;。</p>
<p>这个命令是为了解决，如下shell 命令会产生的问题</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">RUN cd /app</span><br><span class="line">RUN echo "hello" &gt; world.txt</span><br></pre></td></tr></table></figure>
<p>因为每一个run 命令都会产生一个容易所以会导致对应的文件目录不同，通过使用这个名利可以相关的文件目录统一</p>
<h3 id="USER-指定当前用户"><a href="#USER-指定当前用户" class="headerlink" title="USER 指定当前用户"></a>USER 指定当前用户</h3><p>和WORKDIR都是解决docker run类似的命令产生新的容器导致环境不同的问题，只不过WORKDIR针对目录USER针对用户</p>
<h3 id="HEALTHCHECK-健康检查"><a href="#HEALTHCHECK-健康检查" class="headerlink" title="HEALTHCHECK 健康检查"></a>HEALTHCHECK 健康检查</h3><p>格式：</p>
<ul>
<li>HEALTHCHECK [选项] CMD &lt;命令&gt;：设置检查容器健康状况的命令</li>
<li>HEALTHCHECK NONE：如果基础镜像有健康检查指令，使用这行可以屏蔽掉其健康检查指令</li>
</ul>
<p>HEALTHCHECK 指令是告诉 Docker 应该如何进行判断容器的状态是否正常，这是 Docker 1.12 引入的新指令。</p>
<p>HEALTHCHECK 支持下列选项：</p>
<ul>
<li>–interval=&lt;间隔&gt;：两次健康检查的间隔，默认为 30 秒；</li>
<li>–timeout=&lt;时长&gt;：健康检查命令运行超时时间，如果超过这个时间，本次健康检查就被视为失败，默认 30 秒；</li>
<li>–retries=&lt;次数&gt;：当连续失败指定次数后，则将容器状态视为 unhealthy，默认 3 次。<br>和 CMD, ENTRYPOINT 一样，HEALTHCHECK 只可以出现一次，如果写了多个，只有最后一个生效。</li>
</ul>
<p>在 HEALTHCHECK [选项] CMD 后面的命令，格式和 ENTRYPOINT 一样，分为 shell 格式，和 exec 格式。命令的返回值决定了该次健康检查的成功与否：0：成功；1：失败；2：保留，不要使用这个值。</p>
<p>假设我们有个镜像是个最简单的 Web 服务，我们希望增加健康检查来判断其 Web 服务是否在正常工作，我们可以用 curl 来帮助判断，其 Dockerfile 的 HEALTHCHECK 可以这么写：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">FROM nginx</span><br><span class="line">RUN apt-get update &amp;&amp; apt-get install -y curl &amp;&amp; rm -rf /var/lib/apt/lists/*</span><br><span class="line">HEALTHCHECK --interval=5s --timeout=3s \</span><br><span class="line">  CMD curl -fs http://localhost/ || exit 1</span><br></pre></td></tr></table></figure>
<p>当运行该镜像后，可以通过 docker container ls 看到最初的状态为 (health: starting)：<br><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span><span class="bash"> docker container ls</span></span><br><span class="line">CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                            PORTS               NAMES</span><br><span class="line">03e28eb00bd0        myweb:v1            "nginx -g 'daemon off"   3 seconds ago       Up 2 seconds (health: starting)   80/tcp, 443/tcp     web</span><br></pre></td></tr></table></figure></p>
<p>在等待几秒钟后，再次 docker container ls，就会看到健康状态变化为了 (healthy)：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span><span class="bash"> docker container ls</span></span><br><span class="line">CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                    PORTS               NAMES</span><br><span class="line">03e28eb00bd0        myweb:v1            "nginx -g 'daemon off"   18 seconds ago      Up 16 seconds (healthy)   80/tcp, 443/tcp     web</span><br><span class="line">如果健康检查连续失败超过了重试次数，状态就会变为 (unhealthy)。</span><br></pre></td></tr></table></figure>
<h3 id="ONBUILD-为他人做嫁衣裳"><a href="#ONBUILD-为他人做嫁衣裳" class="headerlink" title="ONBUILD 为他人做嫁衣裳"></a>ONBUILD 为他人做嫁衣裳</h3><p>格式：ONBUILD &lt;其它指令&gt;。</p>
<p>ONBUILD 是一个特殊的指令，它后面跟的是其它指令，比如 RUN, COPY 等，而这些指令，在当前镜像构建时并不会被执行。只有当以当前镜像为基础镜像，去构建下一级镜像的时候才会被执行。</p>
<p>Dockerfile 中的其它指令都是为了定制当前镜像而准备的，唯有 ONBUILD 是为了帮助别人定制自己而准备的。</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">FROM node:slim</span><br><span class="line">RUN mkdir /app</span><br><span class="line">WORKDIR /app</span><br><span class="line">ONBUILD COPY ./package.json /app</span><br><span class="line">ONBUILD RUN [ "npm", "install" ]</span><br><span class="line">ONBUILD COPY . /app/</span><br><span class="line">CMD [ "npm", "start" ]</span><br></pre></td></tr></table></figure>

          
        
      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </div>
  
  
  
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/2018/10/09/dubbo学习和使用（一）dubbo架构设计和思想/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="kyssion">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="kyssion-blog">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
                
                <a class="post-title-link" href="/2018/10/09/dubbo学习和使用（一）dubbo架构设计和思想/" itemprop="url">未命名</a></h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2018-10-09T15:22:37+08:00">
                2018-10-09
              </time>
            

            

            
          </span>

          

          
            
          

          
          

          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <h3 id="决定使用dubbo-框架的原因"><a href="#决定使用dubbo-框架的原因" class="headerlink" title="决定使用dubbo 框架的原因"></a>决定使用dubbo 框架的原因</h3><p>考虑了很久，查了很对有关spring cloud 和 dubbo 的对比，最终决定好好研究一下dubbo框架，原因主要有一下的两个方面：</p>
<ol>
<li>dubbo 相比叫spring cloud 感觉rpc调用才是未来发展的框架和基础。</li>
<li>dubbo 相比较spring cloud 来说代码质量和抽象程度更高，研究和学习的点更多</li>
</ol>
<h3 id="目前dubbo存在的问题"><a href="#目前dubbo存在的问题" class="headerlink" title="目前dubbo存在的问题"></a>目前dubbo存在的问题</h3><p>最大的问题，整合spring boot 其余的以后补充</p>
<h3 id="dubbo-项目规范"><a href="#dubbo-项目规范" class="headerlink" title="dubbo 项目规范"></a>dubbo 项目规范</h3><p>其实考察其他的一些rpc 调用框架，无一例外，都存在一个模板，在dubbo 中这种统一的模板被定义成一个统一的包，各个需要调用的接口都继承这个包来进行开发和部署</p>
<h4 id="一个基础的dubbo项目结构"><a href="#一个基础的dubbo项目结构" class="headerlink" title="一个基础的dubbo项目结构"></a>一个基础的dubbo项目结构</h4><p><img src="blogimg/dubbo/n1.png" alt=""></p>
<ul>
<li>dubbo_information: 表示公共的接口类（rpc调用过程中的模板）</li>
<li>dubbo_client : 表示公共接口的客户端</li>
<li>dubbo_service : 表示公共接口的服务端</li>
</ul>
<h3 id="dubbo的作用"><a href="#dubbo的作用" class="headerlink" title="dubbo的作用"></a>dubbo的作用</h3><ul>
<li>作为服务注册中心，动态的注册和发现服务，使服务的位置透明并通过在消费方获取服务提供方地址列表，实现软负载均衡和 Failover（失效备份），降低对 F5 硬件负载均衡器的依赖</li>
<li>自动画出应用间的依赖关系图，以帮助架构师理清理关系。</li>
<li>将服务现在每天的调用量，响应时间，都统计出来，作为容量规划的参考指标，可以动态调整权重，在线上，将某台机器的权重一直加大，并在加大的过程中记录响应时间的变化，直到响应时间到达阀值，记录此时的访问量，再以此访问量乘以机器数反推总容量</li>
</ul>
<h3 id="dubbo的基本架构"><a href="#dubbo的基本架构" class="headerlink" title="dubbo的基本架构"></a>dubbo的基本架构</h3><p><img src="blogimg/dubbo/2.jpg" alt=""></p>
<table>
<thead>
<tr>
<th>节点</th>
<th>角色说明</th>
</tr>
</thead>
<tbody>
<tr>
<td>Provider</td>
<td>暴露服务的服务提供方</td>
</tr>
<tr>
<td>Consumer</td>
<td>调用远程服务的服务消费方</td>
</tr>
<tr>
<td>Registry</td>
<td>服务注册与发现的注册中心</td>
</tr>
<tr>
<td>Monitor</td>
<td>统计服务的调用次调和调用时间的监控中心</td>
</tr>
<tr>
<td>Container</td>
<td>服务运行容器</td>
</tr>
</tbody>
</table>
<p>调用关系说明</p>
<ol start="0">
<li>服务容器负责启动，加载，运行服务提供者。</li>
<li>服务提供者在启动时，向注册中心注册自己提供的服务。</li>
<li>服务消费者在启动时，向注册中心订阅自己所需的服务。</li>
<li>注册中心返回服务提供者地址列表给消费者，如果有变更，注册中心将基于长连接推送变更数据给消费者。</li>
<li>服务消费者，从提供者地址列表中，基于软负载均衡算法，选一台提供者进行调用，如果调用失败，再选另一台调用。</li>
<li>服务消费者和提供者，在内存中累计调用次数和调用时间，定时每分钟发送一次统计数据到监控中心。</li>
</ol>
<h3 id="分布式系统中一些特性"><a href="#分布式系统中一些特性" class="headerlink" title="分布式系统中一些特性"></a>分布式系统中一些特性</h3><p>Dubbo 架构具有以下几个特点，分别是连通性、健壮性、伸缩性、以及向未来架构的升级性。</p>
<h4 id="连通性"><a href="#连通性" class="headerlink" title="连通性"></a>连通性</h4><ul>
<li>注册中心负责服务地址的注册与查找，相当于目录服务，服务提供者和消费者只在启动时与注册中心交互，注册中心不转发请求，压力较小</li>
<li>监控中心负责统计各服务调用次数，调用时间等，统计先在内存汇总后每分钟一次发送到监控中心服务器，并以报表展示</li>
<li>服务提供者向注册中心注册其提供的服务，并汇报调用时间到监控中心，此时间不包含网络开销</li>
<li>服务消费者向注册中心获取服务提供者地址列表，并根据负载算法直接调用提供者，同时汇报调用时间到监控中心，此时间包含网络开销</li>
<li>注册中心，服务提供者，服务消费者三者之间均为长连接，监控中心除外</li>
<li>注册中心通过长连接感知服务提供者的存在，服务提供者宕机，注册中心将立即推送事件通知消费者</li>
<li>注册中心和监控中心全部宕机，不影响已运行的提供者和消费者，消费者在本地缓存了提供者列表</li>
<li>注册中心和监控中心都是可选的，服务消费者可以直连服务提供者</li>
</ul>
<h4 id="健壮性"><a href="#健壮性" class="headerlink" title="健壮性"></a>健壮性</h4><ul>
<li>监控中心宕掉不影响使用，只是丢失部分采样数据</li>
<li>数据库宕掉后，注册中心仍能通过缓存提供服务列表查询，但不能注册新服务</li>
<li>注册中心对等集群，任意一台宕掉后，将自动切换到另一台</li>
<li>注册中心全部宕掉后，服务提供者和服务消费者仍能通过本地缓存通讯</li>
<li>服务提供者无状态，任意一台宕掉后，不影响使用</li>
<li>服务提供者全部宕掉后，服务消费者应用将无法使用，并无限次重连等待服务提供者恢复</li>
</ul>
<h4 id="伸缩性"><a href="#伸缩性" class="headerlink" title="伸缩性"></a>伸缩性</h4><ul>
<li>注册中心为对等集群，可动态增加机器部署实例，所有客户端将自动发现新的注册中心</li>
<li>服务提供者无状态，可动态增加机器部署实例，注册中心将推送新的服务提供者信息给消费者</li>
</ul>
<h4 id="升级性"><a href="#升级性" class="headerlink" title="升级性"></a>升级性</h4><p>当服务集群规模进一步扩大，带动IT治理结构进一步升级，需要实现动态部署，进行流动计算，现有分布式服务架构不会带来阻力。下图是未来可能的一种架构：</p>
<p><img src="blogimg/dubbo/n1.jpg" alt=""></p>
<p>节点角色说明<br>节点|角色说明<br>—|—<br>Deployer|自动部署服务的本地代理<br>Repository|仓库用于存储服务应用发布包<br>Scheduler|调度中心基于访问压力自动增减服务提供者<br>Admin|统一管理控制台<br>Registry|服务注册与发现的注册中心<br>Monitor|统计服务的调用次数和调用时间的监控中心</p>
<h3 id="dubbo-的需求"><a href="#dubbo-的需求" class="headerlink" title="dubbo 的需求"></a>dubbo 的需求</h3><p><img src="blogimg/dubbo/n2.jpg" alt=""></p>
<p>在大规模服务化之前，应用可能只是通过 RMI 或 Hessian 等工具，简单的暴露和引用远程服务，通过配置服务的URL地址进行调用，通过 F5 等硬件进行负载均衡。</p>
<p>当服务越来越多时，服务 URL 配置管理变得非常困难，F5 硬件负载均衡器的单点压力也越来越大。 此时需要一个服务注册中心，动态的注册和发现服务，使服务的位置透明。并通过在消费方获取服务提供方地址列表，实现软负载均衡和 Failover，降低对 F5 硬件负载均衡器的依赖，也能减少部分成本。</p>
<p>当进一步发展，服务间依赖关系变得错踪复杂，甚至分不清哪个应用要在哪个应用之前启动，架构师都不能完整的描述应用的架构关系。 这时，需要自动画出应用间的依赖关系图，以帮助架构师理清理关系。</p>
<p>接着，服务的调用量越来越大，服务的容量问题就暴露出来，这个服务需要多少机器支撑？什么时候该加机器？ 为了解决这些问题，第一步，要将服务现在每天的调用量，响应时间，都统计出来，作为容量规划的参考指标。其次，要可以动态调整权重，在线上，将某台机器的权重一直加大，并在加大的过程中记录响应时间的变化，直到响应时间到达阀值，记录此时的访问量，再以此访问量乘以机器数反推总容量。</p>
<p>以上是 Dubbo 最基本的几个需求。</p>

          
        
      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </div>
  
  
  
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/2018/10/09/dubbo学习和使用（七）dubbo功能（5）/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="kyssion">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="kyssion-blog">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
                
                <a class="post-title-link" href="/2018/10/09/dubbo学习和使用（七）dubbo功能（5）/" itemprop="url">未命名</a></h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2018-10-09T15:22:37+08:00">
                2018-10-09
              </time>
            

            

            
          </span>

          

          
            
          

          
          

          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <p>##配置规则</p>
<p>向注册中心写入动态配置覆盖规则。该功能通常由监控中心或治理中心的页面完成。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension();</span><br><span class="line">Registry registry = registryFactory.getRegistry(URL.valueOf(<span class="string">"zookeeper://10.20.153.10:2181"</span>));</span><br><span class="line">registry.register(URL.valueOf(<span class="string">"override://0.0.0.0/com.foo.BarService?category=configurators&amp;dynamic=false&amp;application=foo&amp;timeout=1000"</span>));</span><br></pre></td></tr></table></figure>
<p>其中：</p>
<ul>
<li>override:// 表示数据采用覆盖方式，支持 override 和 absent，可扩展，必填。</li>
<li>0.0.0.0 表示对所有 IP 地址生效，如果只想覆盖某个 IP 的数据，请填入具体 IP，必填。</li>
<li>com.foo.BarService 表示只对指定服务生效，必填。</li>
<li>category=configurators 表示该数据为动态配置类型，必填。</li>
<li>dynamic=false 表示该数据为持久数据，当注册方退出时，数据依然保存在注册中心，必填。</li>
<li>enabled=true 覆盖规则是否生效，可不填，缺省生效。</li>
<li>application=foo 表示只对指定应用生效，可不填，表示对所有应用生效。</li>
<li>timeout=1000 表示将满足以上条件的 timeout 参数的值覆盖为 1000。如果想覆盖其它参数，直接加在 override 的 URL 参数上。</li>
</ul>
<blockquote>
<p>示例：</p>
</blockquote>
<blockquote>
<p>禁用提供者：(通常用于临时踢除某台提供者机器，相似的，禁止消费者访问请使用路由规则)</p>
</blockquote>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">override://10.20.153.10/com.foo.BarService?category=configurators&amp;dynamic=false&amp;disbaled=true</span><br></pre></td></tr></table></figure>
<blockquote>
<p>调整权重：(通常用于容量评估，缺省权重为 100)</p>
</blockquote>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">override://10.20.153.10/com.foo.BarService?category=configurators&amp;dynamic=false&amp;weight=200</span><br></pre></td></tr></table></figure>
<blockquote>
<p>调整负载均衡策略：(缺省负载均衡策略为 random)</p>
</blockquote>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">override://10.20.153.10/com.foo.BarService?category=configurators&amp;dynamic=false&amp;loadbalance=leastactive</span><br></pre></td></tr></table></figure>
<blockquote>
<p>服务降级：(通常用于临时屏蔽某个出错的非关键服务)</p>
</blockquote>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">override://0.0.0.0/com.foo.BarService?category=configurators&amp;dynamic=false&amp;application</span><br></pre></td></tr></table></figure>
<h2 id="服务降级"><a href="#服务降级" class="headerlink" title="服务降级"></a>服务降级</h2><p>可以通过服务降级功能临时屏蔽某个出错的非关键服务，并定义降级后的返回策略。</p>
<p>向注册中心写入动态配置覆盖规则：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension();</span><br><span class="line">Registry registry = registryFactory.getRegistry(URL.valueOf(<span class="string">"zookeeper://10.20.153.10:2181"</span>));</span><br><span class="line">registry.register(URL.valueOf(<span class="string">"override://0.0.0.0/com.foo.BarService?category=configurators&amp;dynamic=false&amp;application=foo&amp;mock=force:return+null"</span>));</span><br></pre></td></tr></table></figure>
<p>其中：</p>
<ul>
<li>mock=force:return+null 表示消费方对该服务的方法调用都直接返回 null 值，不发起远程调用。用来屏蔽不重要服务不可用时对调用方的影响。</li>
<li>还可以改为 mock=fail:return+null 表示消费方对该服务的方法调用在失败后，再返回 null 值，不抛异常。用来容忍不重要服务不稳定时对调用方的影响。</li>
</ul>
<h2 id="优雅停机"><a href="#优雅停机" class="headerlink" title="优雅停机"></a>优雅停机</h2><p>Dubbo 是通过 JDK 的 ShutdownHook 来完成优雅停机的，所以如果用户使用 kill -9 PID 等强制关闭指令，是不会执行优雅停机的，只有通过 kill PID 时，才会执行。</p>
<p><strong>原理</strong></p>
<blockquote>
<p>服务提供方</p>
</blockquote>
<p>停止时，先标记为不接收新请求，新请求过来时直接报错，让客户端重试其它机器。<br>然后，检测线程池中的线程是否正在运行，如果有，等待所有线程执行完成，除非超时，则强制关闭。</p>
<blockquote>
<p>服务消费方</p>
</blockquote>
<p>停止时，不再发起新的调用请求，所有新的调用在客户端即报错。<br>然后，检测有没有请求的响应还没有返回，等待响应返回，除非超时，则强制关闭。</p>
<blockquote>
<p>设置方式</p>
</blockquote>
<p>设置优雅停机超时时间，缺省超时时间是 10 秒，如果超时则强制关闭。</p>
<h1 id="dubbo-properties"><a href="#dubbo-properties" class="headerlink" title="dubbo.properties"></a>dubbo.properties</h1><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">dubbo.service.shutdown.wait=15000</span><br></pre></td></tr></table></figure>
<p>如果 ShutdownHook 不能生效，可以自行调用，使用tomcat等容器部署的場景，建议通过扩展</p>
<p>ContextListener等自行调用以下代码实现优雅停机：<br><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ProtocolConfig.destroyAll();</span><br></pre></td></tr></table></figure></p>
<h2 id="日志适配"><a href="#日志适配" class="headerlink" title="日志适配"></a>日志适配</h2><p>自 2.2.1 开始，dubbo 开始内置 log4j、slf4j、jcl、jdk 这些日志框架的适配，也可以通过以下方式显示配置日志输出策略：</p>
<blockquote>
<p>命令行</p>
</blockquote>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">java -Ddubbo.application.logger=log4j</span><br></pre></td></tr></table></figure>
<ol start="0">
<li>在 <code>dubbo.properties</code> 中指定</li>
</ol>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">dubbo.application.logger=log4j</span><br></pre></td></tr></table></figure>
<p>在 dubbo.xml 中配置</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:application</span> <span class="attr">logger</span>=<span class="string">"log4j"</span> /&gt;</span></span><br></pre></td></tr></table></figure>
<h2 id="开启访问日志"><a href="#开启访问日志" class="headerlink" title="开启访问日志"></a>开启访问日志</h2><p>如果你想记录每一次请求信息，可开启访问日志，类似于apache的访问日志。注意：此日志量比较大，请注意磁盘容量。</p>
<p>将访问日志输出到当前应用的log4j日志：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:protocol</span> <span class="attr">accesslog</span>=<span class="string">"true"</span> /&gt;</span></span><br></pre></td></tr></table></figure>
<p>将访问日志输出到指定文件：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:protocol</span> <span class="attr">accesslog</span>=<span class="string">"http://10.20.160.198/wiki/display/dubbo/foo/bar.log"</span> /&gt;</span></span><br></pre></td></tr></table></figure>
<h2 id="服务容器"><a href="#服务容器" class="headerlink" title="服务容器"></a>服务容器</h2><p>服务容器是一个 standalone 的启动程序，因为后台服务不需要 Tomcat 或 JBoss 等 Web 容器的功能，如果硬要用 Web 容器去加载服务提供方，增加复杂性，也浪费资源。</p>
<p>服务容器只是一个简单的 Main 方法，并加载一个简单的 Spring 容器，用于暴露服务。</p>
<p>服务容器的加载内容可以扩展，内置了 spring, jetty, log4j 等加载，可通过容器扩展点进行扩展。配置配在 java 命令的 -D 参数或者 dubbo.properties 中。</p>
<blockquote>
<p>容器类型</p>
</blockquote>
<p>Spring Container</p>
<p>自动加载 META-INF/spring 目录下的所有 Spring 配置。</p>
<p>配置 spring 配置加载位置：</p>
<p>dubbo.spring.config=classpath<em>:META-INF/spring/</em>.xml</p>
<h3 id="Jetty-Container"><a href="#Jetty-Container" class="headerlink" title="Jetty Container"></a>Jetty Container</h3><ul>
<li>启动一个内嵌 Jetty，用于汇报状态。</li>
<li>配置：<ul>
<li><code>dubbo.jetty.port=8080</code>：配置 jetty 启动端口</li>
<li><code>dubbo.jetty.directory=/foo/bar</code>：配置可通过 jetty 直接访问的目录，用于存放静态文件</li>
<li><code>dubbo.jetty.page=log,status,system</code>：配置显示的页面，缺省加载所有页面</li>
</ul>
</li>
</ul>
<h3 id="Log4j-Container"><a href="#Log4j-Container" class="headerlink" title="Log4j Container"></a>Log4j Container</h3><ul>
<li>自动配置 log4j 的配置，在多进程启动时，自动给日志文件按进程分目录。</li>
<li>配置：<ul>
<li><code>dubbo.log4j.file=/foo/bar.log</code>：配置日志文件路径</li>
<li><code>dubbo.log4j.level=WARN</code>：配置日志级别</li>
<li><code>dubbo.log4j.subdirectory=20880</code>：配置日志子目录，用于多进程启动，避免冲突</li>
</ul>
</li>
</ul>
<h2 id="容器启动"><a href="#容器启动" class="headerlink" title="容器启动"></a>容器启动</h2><p>缺省只加载 spring</p>
<figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">java com.alibaba.dubbo.container.Main</span><br><span class="line">通过 main 函数参数传入要加载的容器</span><br><span class="line"></span><br><span class="line">java com.alibaba.dubbo.container.Main spring jetty log4j</span><br><span class="line">通过 JVM 启动参数传入要加载的容器</span><br><span class="line"></span><br><span class="line">java com.alibaba.dubbo.container.Main -Ddubbo.container=spring,jetty,log4j</span><br><span class="line">通过 classpath 下的 dubbo.properties 配置传入要加载的容器</span><br><span class="line"></span><br><span class="line">dubbo.container=spring,jetty,log4j</span><br></pre></td></tr></table></figure>
<h2 id="ReferenceConfig-缓存"><a href="#ReferenceConfig-缓存" class="headerlink" title="ReferenceConfig 缓存"></a>ReferenceConfig 缓存</h2><p>ReferenceConfig 实例很重，封装了与注册中心的连接以及与提供者的连接，需要缓存。否则重复生成 ReferenceConfig 可能造成性能问题并且会有内存和连接泄漏。在 API 方式编程时，容易忽略此问题。</p>
<p>因此，自 2.4.0 版本开始， dubbo 提供了简单的工具类 ReferenceConfigCache用于缓存 ReferenceConfig 实例。</p>
<p>使用方式如下：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">ReferenceConfig&lt;XxxService&gt; reference = <span class="keyword">new</span> ReferenceConfig&lt;XxxService&gt;();</span><br><span class="line">reference.setInterface(XxxService.class);</span><br><span class="line">reference.setVersion(<span class="string">"1.0.0"</span>);</span><br><span class="line">......</span><br><span class="line">ReferenceConfigCache cache = ReferenceConfigCache.getCache();</span><br><span class="line"><span class="comment">// cache.get方法中会缓存 Reference对象，并且调用ReferenceConfig.get方法启动ReferenceConfig</span></span><br><span class="line">XxxService xxxService = cache.get(reference);</span><br><span class="line"><span class="comment">// 注意！ Cache会持有ReferenceConfig，不要在外部再调用ReferenceConfig的destroy方法，导致Cache内的ReferenceConfig失效！</span></span><br><span class="line"><span class="comment">// 使用xxxService对象</span></span><br><span class="line">xxxService.sayHello();</span><br></pre></td></tr></table></figure>
<p>消除 Cache 中的 ReferenceConfig，将销毁 ReferenceConfig 并释放对应的资源。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">ReferenceConfigCache cache = ReferenceConfigCache.getCache();</span><br><span class="line">cache.destroy(reference);</span><br></pre></td></tr></table></figure>
<p>缺省 ReferenceConfigCache 把相同服务 Group、接口、版本的 ReferenceConfig 认为是相同，缓存一份。即以服务 Group、接口、版本为缓存的 Key。</p>
<p>可以修改这个策略，在 ReferenceConfigCache.getCache 时，传一个 KeyGenerator。详见 ReferenceConfigCache 类的方法。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">KeyGenerator keyGenerator = <span class="keyword">new</span> ...</span><br><span class="line">ReferenceConfigCache cache = ReferenceConfigCache.getCache(keyGenerator );</span><br></pre></td></tr></table></figure>
<h2 id="现场dump"><a href="#现场dump" class="headerlink" title="现场dump"></a>现场dump</h2><p>当业务线程池满时，我们需要知道线程都在等待哪些资源、条件，以找到系统的瓶颈点或异常点。dubbo通过Jstack自动导出线程堆栈来保留现场，方便排查问题</p>
<p>默认策略:</p>
<p>导出路径，user.home标识的用户主目录<br>导出间隔，最短间隔允许每隔10分钟导出一次<br>指定导出路径：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">dubbo.application.dump.directory=/tmp</span><br></pre></td></tr></table></figure>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">dubbo:application</span> <span class="attr">...</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">dubbo:parameter</span> <span class="attr">key</span>=<span class="string">"dump.directory"</span> <span class="attr">value</span>=<span class="string">"/tmp"</span> /&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">dubbo:application</span>&gt;</span></span><br></pre></td></tr></table></figure>
          
        
      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </div>
  
  
  
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/2018/10/09/docker（二）镜像使用和命令/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="kyssion">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="kyssion-blog">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
                
                <a class="post-title-link" href="/2018/10/09/docker（二）镜像使用和命令/" itemprop="url">未命名</a></h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2018-10-09T15:22:37+08:00">
                2018-10-09
              </time>
            

            

            
          </span>

          

          
            
          

          
          

          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <h3 id="获取镜像-pull"><a href="#获取镜像-pull" class="headerlink" title="获取镜像 pull"></a>获取镜像 pull</h3><p>关键命令</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker pull [选项] [Docker Registry 地址[:端口号]/]仓库名[:标签]</span><br></pre></td></tr></table></figure>
<p>命名格式</p>
<ul>
<li>Docker 镜像仓库地址：地址的格式一般是 &lt;域名/IP&gt;[:端口号]。默认地址是 Docker Hub。</li>
<li>仓库名：如之前所说，这里的仓库名是两段式名称，即 &lt;用户名&gt;/&lt;软件名&gt;。对于 Docker Hub，如果不给出用户名，则默认为 library，也就是官方镜像。</li>
</ul>
<h3 id="运行镜像-run"><a href="#运行镜像-run" class="headerlink" title="运行镜像 run"></a>运行镜像 run</h3><p>镜像格式</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run [OPTIONS] IMAGE [COMMAND] [ARG...]</span><br></pre></td></tr></table></figure>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run -it --rm ubuntu:16.04 bash</span><br></pre></td></tr></table></figure>
<p>启动容器有两种方式，一种是基于镜像新建一个容器并启动，另外一个是将在终止状态（stopped）的容器重新启动。</p>
<p>因为 Docker 的容器实在太轻量级了，很多时候用户都是随时删除和新创建容器。</p>
<p>OPTIONS说明：</p>
<ul>
<li><p>-a stdin: 指定标准输入输出内容类型，可选 STDIN/STDOUT/STDERR 三项；</p>
</li>
<li><p>-d: 后台运行容器，并返回容器ID；</p>
</li>
<li><p>-i: 以交互模式运行容器，通常与 -t 同时使用；</p>
</li>
<li><p>-t: 为容器重新分配一个伪输入终端，通常与 -i 同时使用；</p>
</li>
<li><p>–name=”nginx-lb”: 为容器指定一个名称；</p>
</li>
<li><p>–dns 8.8.8.8: 指定容器使用的DNS服务器，默认和宿主一致；</p>
</li>
<li><p>–dns-search example.com: 指定容器DNS搜索域名，默认和宿主一致；</p>
</li>
<li><p>-h “mars”: 指定容器的hostname；</p>
</li>
<li><p>-e username=”ritchie”: 设置环境变量；</p>
</li>
<li><p>–env-file=[]: 从指定文件读入环境变量；</p>
</li>
<li><p>–cpuset=”0-2” or –cpuset=”0,1,2”: 绑定容器到指定CPU运行；</p>
</li>
<li><p>-m :设置容器使用内存最大值；</p>
</li>
<li><p>–net=”bridge”: 指定容器的网络连接类型，支持 bridge/host/none/container: 四种类型；</p>
</li>
<li><p>–link=[]: 添加链接到另一个容器；</p>
</li>
<li><p>–expose=[]: 开放一个端口或一组端口；</p>
</li>
</ul>
<p>当利用 docker run 来创建容器时，Docker 在后台运行的标准操作包括：</p>
<ul>
<li>检查本地是否存在指定的镜像，不存在就从公有仓库下载</li>
<li>利用镜像创建并启动一个容器</li>
<li>分配一个文件系统，并在只读的镜像层外面挂载一层可读写层</li>
<li>从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去</li>
<li>从地址池配置一个 ip 地址给容器</li>
<li>执行用户指定的应用程序</li>
<li>执行完毕后容器被终止</li>
</ul>
<h3 id="docker-container-start"><a href="#docker-container-start" class="headerlink" title="docker container start"></a>docker container start</h3><h3 id="列出镜像-image-ls"><a href="#列出镜像-image-ls" class="headerlink" title="列出镜像 image ls"></a>列出镜像 image ls</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker image ls</span><br></pre></td></tr></table></figure>
<p>打印输出所有的镜像</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE</span><br><span class="line">nginx               v3                  57bd2e54ef1b        24 hours ago        109MB</span><br><span class="line">nginx               latest              5699ececb21c        6 days ago          109MB</span><br><span class="line">ubuntu              16.04               5e8b97a2a082        3 weeks ago         114MB</span><br><span class="line">hello-world         latest              e38bc07ac18e        2 months ago        1.85kB</span><br></pre></td></tr></table></figure>
<h4 id="查看docker-磁盘的使用情况"><a href="#查看docker-磁盘的使用情况" class="headerlink" title="查看docker 磁盘的使用情况"></a>查看docker 磁盘的使用情况</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker system df</span><br></pre></td></tr></table></figure>
<p>注意：这里引申一下docker image 命令显示出来的各种信息，docker image ls 列表中的镜像体积总和并非是所有镜像实际硬盘消耗。由于 Docker 镜像是多层存储结构，并且可以继承、复用，因此不同镜像可能会因为使用相同的基础镜像，从而拥有共同的层。由于 Docker 使用 Union FS，相同的层只需要保存一份即可，因此实际镜像硬盘占用空间很可能要比这个列表镜像大小的总和要小的多。</p>
<h4 id="特殊的玄虚镜像"><a href="#特殊的玄虚镜像" class="headerlink" title="特殊的玄虚镜像"></a>特殊的玄虚镜像</h4><p>由于新旧镜像同名，旧镜像名称被取消等，出现仓库名、标签均为 <none> 的镜像。这类无标签镜像也被称为 虚悬镜像(dangling image)</none></p>
<blockquote>
<p>使用这个命令将会直接的看到这些镜像</p>
</blockquote>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">$ docker image ls -f dangling=true</span><br><span class="line">REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE</span><br><span class="line">&lt;none&gt;              &lt;none&gt;              00285df0df87        5 days ago          342 MB</span><br></pre></td></tr></table></figure>
<blockquote>
<p>一般来说，虚悬镜像已经失去了存在的价值，是可以随意删除的，可以用下面的命令删除。</p>
</blockquote>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span> docker image prune</span><br></pre></td></tr></table></figure>
<h4 id="中间层镜像"><a href="#中间层镜像" class="headerlink" title="中间层镜像"></a>中间层镜像</h4><p>默认的 docker image ls 列表中只会显示顶层镜像，如果希望显示包括中间层镜像在内的所有镜像的话，需要加 -a 参数。</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span> docker image ls -a</span><br></pre></td></tr></table></figure>
<p>这样会看到很多无标签的镜像，与之前的虚悬镜像不同，这些无标签的镜像很多都是中间层镜像，是其它镜像所依赖的镜像。这些无标签镜像不应该删除，否则会导致上层镜像因为依赖丢失而出错。实际上，这些镜像也没必要删除，因为之前说过，相同的层只会存一遍，而这些镜像是别的镜像的依赖，因此并不会因为它们被列出来而多存了一份，无论如何你也会需要它们。只要删除那些依赖它们的镜像后，这些依赖的中间层镜像也会被连带删除。</p>
<h4 id="列出部分镜像"><a href="#列出部分镜像" class="headerlink" title="列出部分镜像"></a>列出部分镜像</h4><p>不加任何参数的情况下，docker image ls 会列出所有顶级镜像，但是有时候我们只希望列出部分镜像。docker image ls 有好几个参数可以帮助做到这个事情。</p>
<blockquote>
<p>根据仓库名列出镜像<br><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span> docker image ls ubuntu</span><br><span class="line">REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE</span><br><span class="line">ubuntu              16.04               f753707788c5        4 weeks ago         127 MB</span><br><span class="line">ubuntu              latest              f753707788c5        4 weeks ago         127 MB</span><br><span class="line">ubuntu              14.04               1e0c3dd64ccd        4 weeks ago         188 MB</span><br></pre></td></tr></table></figure></p>
</blockquote>
<blockquote>
<p>显示镜像详细信息</p>
</blockquote>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span> docker image ls --digests</span><br></pre></td></tr></table></figure>
<p>这个方法将会显示出这个镜像的长id等信息</p>
<blockquote>
<p>列出特定的某个镜像，也就是说指定仓库名和标签</p>
</blockquote>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span> docker image ls ubuntu:16.04</span><br><span class="line">REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE</span><br><span class="line">ubuntu              16.04               f753707788c5        4 weeks ago         127 MB</span><br></pre></td></tr></table></figure>
<blockquote>
<p>docker image ls 还支持强大的过滤器参数 –filter，或者简写 -f</p>
</blockquote>
<p>比如，我们希望看到在 mongo:3.2 之后建立的镜像，可以用下面的命令：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span> docker image ls -f since=mongo:3.2</span><br><span class="line">REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE</span><br><span class="line">redis               latest              5f515359c7f8        5 days ago          183 MB</span><br><span class="line">nginx               latest              05a60462f8ba        5 days ago          181 MB</span><br></pre></td></tr></table></figure>
<blockquote>
<p>想查看某个位置之前的镜像也可以，只需要把 since 换成 before 即可。</p>
</blockquote>
<h4 id="利用-docker-image-ls-把所有的虚悬镜像的-ID-列出来"><a href="#利用-docker-image-ls-把所有的虚悬镜像的-ID-列出来" class="headerlink" title="利用 docker image ls 把所有的虚悬镜像的 ID 列出来"></a>利用 docker image ls 把所有的虚悬镜像的 ID 列出来</h4><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span> docker image ls -q</span><br><span class="line">5f515359c7f8</span><br><span class="line">05a60462f8ba</span><br><span class="line">fe9198c04d62</span><br><span class="line">00285df0df87</span><br><span class="line">f753707788c5</span><br><span class="line">f753707788c5</span><br><span class="line">1e0c3dd64ccd</span><br></pre></td></tr></table></figure>
<h4 id="配合使用go-模板语法"><a href="#配合使用go-模板语法" class="headerlink" title="配合使用go 模板语法"></a>配合使用go 模板语法</h4><p>下面的命令会直接列出镜像结果，并且只包含镜像ID和仓库名：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span> docker image ls --format "&#123;&#123;.ID&#125;&#125;: &#123;&#123;.Repository&#125;&#125;"</span><br><span class="line">5f515359c7f8: redis</span><br><span class="line">05a60462f8ba: nginx</span><br><span class="line">fe9198c04d62: mongo</span><br><span class="line">00285df0df87: &lt;none&gt;</span><br><span class="line">f753707788c5: ubuntu</span><br><span class="line">f753707788c5: ubuntu</span><br><span class="line">1e0c3dd64ccd: ubuntu</span><br></pre></td></tr></table></figure>
<p>或者打算以表格等距显示，并且有标题行，和默认一样，不过自己定义列：<br><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span> docker image ls --format "table &#123;&#123;.ID&#125;&#125;\t&#123;&#123;.Repository&#125;&#125;\t&#123;&#123;.Tag&#125;&#125;"</span><br><span class="line">IMAGE ID            REPOSITORY          TAG</span><br><span class="line">5f515359c7f8        redis               latest</span><br><span class="line">05a60462f8ba        nginx               latest</span><br><span class="line">fe9198c04d62        mongo               3.2</span><br><span class="line">00285df0df87        &lt;none&gt;              &lt;none&gt;</span><br><span class="line">f753707788c5        ubuntu              16.04</span><br><span class="line">f753707788c5        ubuntu              latest</span><br><span class="line">1e0c3dd64ccd        ubuntu              14.04</span><br></pre></td></tr></table></figure></p>
<h3 id="删除本地镜像"><a href="#删除本地镜像" class="headerlink" title="删除本地镜像"></a>删除本地镜像</h3><h4 id="用-ID、镜像名、摘要删除镜像"><a href="#用-ID、镜像名、摘要删除镜像" class="headerlink" title="用 ID、镜像名、摘要删除镜像"></a>用 ID、镜像名、摘要删除镜像</h4><p>如果要删除本地的镜像，可以使用 docker image rm 命令，其格式为：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span> docker image rm [选项] &lt;镜像1&gt; [&lt;镜像2&gt; ...]</span><br></pre></td></tr></table></figure>
<p>&lt;镜像&gt; 可以是 镜像短 ID、镜像长 ID、镜像名(&lt;仓库名&gt;:&lt;标签&gt;) 或者 镜像摘要</p>
<blockquote>
<p>引申： 短id 其实就是docker image ls 展示的相关的id</p>
</blockquote>
<h4 id="Untagged-和-Deleted"><a href="#Untagged-和-Deleted" class="headerlink" title="Untagged 和 Deleted"></a>Untagged 和 Deleted</h4><p>首先观察一个删除的命令和结果</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span> docker image rm centos</span><br><span class="line">Untagged: centos:latest</span><br><span class="line">Untagged: centos@sha256:b2f9d1c0ff5f87a4743104d099a3d561002ac500db1b9bfa02a783a46e0d366c</span><br><span class="line">Deleted: sha256:0584b3d2cf6d235ee310cf14b54667d889887b838d3f3d3033acd70fc3c48b8a</span><br><span class="line">Deleted: sha256:97ca462ad9eeae25941546209454496e1d66749d53dfa2ee32bf1faabd239d38</span><br></pre></td></tr></table></figure>
<p>删除行为分为两类，一类是 Untagged，另一类是 Deleted。我们之前介绍过，镜像的唯一标识是其 ID 和摘要，而一个镜像可以有多个标签。</p>
<p>因此当我们使用上面命令删除镜像的时候，实际上是在要求删除某个标签的镜像。所以首先需要做的是将满足我们要求的所有镜像标签都取消，这就是我们看到的 Untagged 的信息。因为一个镜像可以对应多个标签，因此当我们删除了所指定的标签后，可能还有别的标签指向了这个镜像，如果是这种情况，那么 Delete 行为就不会发生。所以并非所有的 docker image rm 都会产生删除镜像的行为，有可能仅仅是取消了某个标签而已。</p>
<p>当该镜像所有的标签都被取消了，该镜像很可能会失去了存在的意义，因此会触发删除行为。镜像是多层存储结构，因此在删除的时候也是从上层向基础层方向依次进行判断删除。镜像的多层结构让镜像复用变动非常容易，因此很有可能某个其它镜像正依赖于当前镜像的某一层。这种情况，依旧不会触发删除该层的行为。直到没有任何层依赖当前层时，才会真实的删除当前层。这就是为什么，有时候会奇怪，为什么明明没有别的标签指向这个镜像，但是它还是存在的原因，也是为什么有时候会发现所删除的层数和自己 docker pull 看到的层数不一样的源。</p>
<p>除了镜像依赖以外，还需要注意的是容器对镜像的依赖。如果有用这个镜像启动的容器存在（即使容器没有运行），那么同样不可以删除这个镜像。之前讲过，容器是以镜像为基础，再加一层容器存储层，组成这样的多层存储结构去运行的。因此该镜像如果被这个容器所依赖的，那么删除必然会导致故障。如果这些容器是不需要的，应该先将它们删除，然后再来删除镜像。</p>
<h4 id="用-docker-image-ls-命令来配合"><a href="#用-docker-image-ls-命令来配合" class="headerlink" title="用 docker image ls 命令来配合"></a>用 docker image ls 命令来配合</h4><p>像其它可以承接多个实体的命令一样，可以使用 docker image ls -q 来配合使用 docker image rm，这样可以成批的删除希望删除的镜像。我们在“镜像列表”章节介绍过很多过滤镜像列表的方式都可以拿过来使用。</p>
<blockquote>
<p>比如，我们需要删除所有仓库名为 redis 的镜像：</p>
</blockquote>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span> docker image rm $(docker image ls -q redis)</span><br></pre></td></tr></table></figure>
<blockquote>
<p>或者删除所有在 mongo:3.2 之前的镜像：</p>
</blockquote>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span> docker image rm $(docker image ls -q -f before=mongo:3.2)</span><br></pre></td></tr></table></figure>
<blockquote>
<p>充分利用你的想象力和 Linux 命令行的强大，你可以完成很多非常赞的功能。</p>
</blockquote>
<h3 id="docker-commit-命令和相关的问题"><a href="#docker-commit-命令和相关的问题" class="headerlink" title="docker commit 命令和相关的问题"></a>docker commit 命令和相关的问题</h3><p>docker commit 的语法格式为：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker commit [选项] &lt;容器ID或容器名&gt; [&lt;仓库名&gt;[:&lt;标签&gt;]]</span><br></pre></td></tr></table></figure>
<p>可以使用如下的方法将指定的容器打包成镜像</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span> docker commit \</span><br><span class="line">    --author "Tao Wang &lt;twang2218@gmail.com&gt;" \</span><br><span class="line">    --message "修改了默认网页" \</span><br><span class="line">    webserver \</span><br><span class="line">    nginx:v2</span><br><span class="line">sha256:07e33465974800ce65751acc279adc6ed2dc5ed4e0838f8b86f0c87aa1795214</span><br></pre></td></tr></table></figure>
<blockquote>
<p>引申：其中 –author 是指定修改的作者，而 –message 则是记录本次修改的内容。这点和 git 版本控制相似，不过这里这些信息可以省略留空。</p>
</blockquote>
<p>使用 docker commit 命令虽然可以比较直观的帮助理解镜像分层存储的概念，但是实际环境中并不会这样使用。</p>
<p>首先，如果仔细观察之前的 docker diff webserver 的结果，你会发现除了真正想要修改的 /usr/share/nginx/html/index.html 文件外，由于命令的执行，还有很多文件被改动或添加了。这还仅仅是最简单的操作，如果是安装软件包、编译构建，那会有大量的无关内容被添加进来，如果不小心清理，将会导致镜像极为臃肿。</p>
<p>此外，使用 docker commit 意味着所有对镜像的操作都是黑箱操作，生成的镜像也被称为黑箱镜像，换句话说，就是除了制作镜像的人知道执行过什么命令、怎么生成的镜像，别人根本无从得知。而且，即使是这个制作镜像的人，过一段时间后也无法记清具体在操作的。虽然 docker diff 或许可以告诉得到一些线索，但是远远不到可以确保生成一致镜像的地步。这种黑箱镜像的维护工作是非常痛苦的。</p>
<blockquote>
<p>注意： 应该使用dockerfile 进行相关的镜像生成和维护工作</p>
</blockquote>

          
        
      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </div>
  
  
  
  </article>


    
      

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://yoursite.com/2018/10/09/docker（三）dockerfile定制镜像/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="kyssion">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="kyssion-blog">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
                
                <a class="post-title-link" href="/2018/10/09/docker（三）dockerfile定制镜像/" itemprop="url">未命名</a></h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2018-10-09T15:22:37+08:00">
                2018-10-09
              </time>
            

            

            
          </span>

          

          
            
          

          
          

          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        
          
            <h3 id="使用-Dockerfile-定制镜像"><a href="#使用-Dockerfile-定制镜像" class="headerlink" title="使用 Dockerfile 定制镜像"></a>使用 Dockerfile 定制镜像</h3><p>从刚才的 docker commit 的学习中，我们可以了解到，镜像的定制实际上就是定制每一层所添加的配置、文件。如果我们可以把每一层修改、安装、构建、操作的命令都写入一个脚本，用这个脚本来构建、定制镜像，那么之前提及的无法重复的问题、镜像构建透明性的问题、体积的问题就都会解决。这个脚本就是 Dockerfile。</p>
<p>Dockerfile 是一个文本文件，其内包含了一条条的指令(Instruction)，每一条指令构建一层，因此每一条指令的内容，就是描述该层应当如何构建。</p>
<h3 id="docker-指令"><a href="#docker-指令" class="headerlink" title="docker 指令"></a>docker 指令</h3><h4 id="FROM-指定基础镜像"><a href="#FROM-指定基础镜像" class="headerlink" title="FROM 指定基础镜像"></a>FROM 指定基础镜像</h4><p>所谓定制镜像，那一定是以一个镜像为基础，在其上进行定制。就像我们之前运行了一个 nginx 镜像的容器，再进行修改一样，基础镜像是必须指定的。而 FROM 就是指定基础镜像，因此一个 Dockerfile 中 FROM 是必备的指令，并且必须是第一条指令。</p>
<p>From 命令可以制定特定的服务类的镜像如 nginx、redis、mongo、mysql、httpd、php、tomcat 等，或者编程语言镜像如 node、openjdk、python、ruby、golang 等，或者操作系统如 ubuntu、debian、centos、fedora、alpine 等，或者使用空白镜像scratch（这个镜像只能运行可执行文件）</p>
<h4 id="run-命令"><a href="#run-命令" class="headerlink" title="run 命令"></a>run 命令</h4><p>RUN 指令是用来执行命令行命令的。由于命令行的强大能力，RUN 指令在定制镜像时是最常用的指令之一。其格式有两种：</p>
<ul>
<li>shell 格式：RUN &lt;命令&gt;，就像直接在命令行中输入的命令一样。刚才写的 Dockerfile 中的 RUN 指令就是这种格式。</li>
</ul>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">RUN echo '&lt;h1&gt;Hello, Docker!&lt;/h1&gt;' &gt; /usr/share/nginx/html/index.html</span><br></pre></td></tr></table></figure>
<ul>
<li>exec 格式：RUN [“可执行文件”, “参数1”, “参数2”]，这更像是函数调用中的格式。</li>
</ul>
<p>注意：RUN 就像 Shell 脚本一样可以执行命令，那么我们不能就可以像 Shell 脚本一样把每个命令对应一个 RUN，比如这样</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">FROM debian:jessie</span><br><span class="line"></span><br><span class="line">RUN apt-get update</span><br><span class="line">RUN apt-get install -y gcc libc6-dev make</span><br><span class="line">RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-3.2.5.tar.gz"</span><br><span class="line">RUN mkdir -p /usr/src/redis</span><br><span class="line">RUN tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1</span><br><span class="line">RUN make -C /usr/src/redis</span><br><span class="line">RUN make -C /usr/src/redis install</span><br></pre></td></tr></table></figure>
<p>因为Dockerfile 中每一个指令都会建立一层，RUN 也不例外。每一个 RUN 的行为，就和刚才我们手工建立镜像的过程一样：新建立一层，在其上执行这些命令，执行结束后，commit 这一层的修改，构成新的镜像。上面的这种写法，创建了 7 层镜像。这是完全没有意义的，而且很多运行时不需要的东西，都被装进了镜像里，比如编译环境、更新的软件包等等。结果就是产生非常臃肿、非常多层的镜像，不仅仅增加了构建部署的时间，也很容易出错</p>
<p>正确的写法应该是这样：</p>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">FROM debian:jessie</span><br><span class="line"></span><br><span class="line">RUN buildDeps='gcc libc6-dev make' \</span><br><span class="line">    &amp;&amp; apt-get update \</span><br><span class="line">    &amp;&amp; apt-get install -y $buildDeps \</span><br><span class="line">    &amp;&amp; wget -O redis.tar.gz "http://download.redis.io/releases/redis-3.2.5.tar.gz" \</span><br><span class="line">    &amp;&amp; mkdir -p /usr/src/redis \</span><br><span class="line">    &amp;&amp; tar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1 \</span><br><span class="line">    &amp;&amp; make -C /usr/src/redis \</span><br><span class="line">    &amp;&amp; make -C /usr/src/redis install \</span><br><span class="line">    &amp;&amp; rm -rf /var/lib/apt/lists/* \</span><br><span class="line">    &amp;&amp; rm redis.tar.gz \</span><br><span class="line">    &amp;&amp; rm -r /usr/src/redis \</span><br><span class="line">    &amp;&amp; apt-get purge -y --auto-remove $buildDeps</span><br></pre></td></tr></table></figure>
<p>并且，这里为了格式化还进行了换行。Dockerfile 支持 Shell 类的行尾添加 \ 的命令换行方式，以及行首 # 进行注释的格式。良好的格式，比如换行、缩进、注释等，会让维护、排障更为容易，这是一个比较好的习惯。</p>
<p>此外，还可以看到这一组命令的最后添加了清理工作的命令，删除了为了编译构建所需要的软件，清理了所有下载、展开的文件，并且还清理了 apt 缓存文件。这是很重要的一步，我们之前说过，镜像是多层存储，每一层的东西并不会在下一层被删除，会一直跟随着镜像。因此镜像构建时，一定要确保每一层只添加真正需要添加的东西，任何无关的东西都应该清理掉。</p>
<h3 id="docker-build命令"><a href="#docker-build命令" class="headerlink" title="docker build命令"></a>docker build命令</h3><p>docker build 命令将会自动的将docker file 文件进行运行构建出镜像</p>
<p>下面使用的dockerfile 文件</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">FROM nginx</span><br><span class="line">RUN echo &apos;&lt;h1&gt;Hello, Docker!&lt;/h1&gt;&apos; &gt; /usr/share/nginx/html/index.html</span><br></pre></td></tr></table></figure>
<figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">kys@kys-virtual-machine:~/docker_study$ sudo docker build -t nginx:v4 .</span><br><span class="line">Sending build context to Docker daemon  2.048kB</span><br><span class="line">Step 1/2 : FROM nginx</span><br><span class="line"><span class="meta"> ---&gt;</span> 5699ececb21c</span><br><span class="line">Step 2/2 : RUN echo '&lt;h1&gt;Hello, Docker!&lt;/h1&gt;' &gt; /usr/share/nginx/html/index.html</span><br><span class="line"><span class="meta"> ---&gt;</span> Using cache</span><br><span class="line"><span class="meta"> ---&gt;</span> 57bd2e54ef1b</span><br><span class="line">Successfully built 57bd2e54ef1b</span><br><span class="line">Successfully tagged nginx:v4</span><br></pre></td></tr></table></figure>
<p>从命令的输出结果中，我们可以清晰的看到镜像的构建过程。在 Step 2 中，如同我们之前所说的那样，RUN 指令启动了一个容器 9cdc27646c7b，执行了所要求的命令，并最后提交了这一层 44aa4490ce2c，随后删除了所用到的这个容器 9cdc27646c7b。</p>
<blockquote>
<p>docker 使用dockerfile构建镜像的过程</p>
</blockquote>
<p>首先我们要理解 docker build 的工作原理。Docker 在运行时分为 Docker 引擎（也就是服务端守护进程）和客户端工具。Docker 的引擎提供了一组 REST API，被称为 Docker Remote API，而如 docker 命令这样的客户端工具，则是通过这组 API 与 Docker 引擎交互，从而完成各种功能。因此，虽然表面上我们好像是在本机执行各种 docker 功能，但实际上，一切都是使用的远程调用形式在服务端（Docker 引擎）完成。也因为这种 C/S 设计，让我们操作远程服务器的 Docker 引擎变得轻而易举。</p>
<p>当我们进行镜像构建的时候，并非所有定制都会通过 RUN 指令完成，经常会需要将一些本地文件复制进镜像，比如通过 COPY 指令、ADD 指令等。而 docker build 命令构建镜像，其实并非在本地构建，而是在服务端，也就是 Docker 引擎中构建的。</p>
<p>那么在这种客户端/服务端的架构中，如何才能让服务端获得本地文件呢？</p>
<p>这就引入了上下文的概念。当构建的时候，用户会指定构建镜像上下文的路径，docker build 命令得知这个路径后，会将路径下的所有内容打包，然后上传给 Docker 引擎。这样 Docker 引擎收到这个上下文包后，展开就会获得构建镜像所需的一切文件。— 这里简单地说就是系统将 制定的自己的目录的信息打包到docker中（注意并不是在容器）</p>

          
        
      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      

      

      
      
        <div class="post-eof"></div>
      
    </footer>
  </div>
  
  
  
  </article>


    
  </section>

  
  <nav class="pagination">
    <a class="extend prev" rel="prev" href="/page/10/"><i class="fa fa-angle-left"></i></a><a class="page-number" href="/">1</a><span class="space">&hellip;</span><a class="page-number" href="/page/10/">10</a><span class="page-number current">11</span><a class="page-number" href="/page/12/">12</a><span class="space">&hellip;</span><a class="page-number" href="/page/14/">14</a><a class="extend next" rel="next" href="/page/12/"><i class="fa fa-angle-right"></i></a>
  </nav>



          </div>
          


          

        </div>
        
          
  
  <div class="sidebar-toggle">
    <div class="sidebar-toggle-line-wrap">
      <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
    </div>
  </div>

  <aside id="sidebar" class="sidebar">
    
    <div class="sidebar-inner">

      

      

      <section class="site-overview-wrap sidebar-panel sidebar-panel-active">
        <div class="site-overview">
          <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
            
              <p class="site-author-name" itemprop="name">kyssion</p>
              <p class="site-description motion-element" itemprop="description"></p>
          </div>

          <nav class="site-state motion-element">

            
              <div class="site-state-item site-state-posts">
              
                <a href="/archives/">
              
                  <span class="site-state-item-count">133</span>
                  <span class="site-state-item-name">日志</span>
                </a>
              </div>
            

            
              
              
              <div class="site-state-item site-state-categories">
                
                  <span class="site-state-item-count">3</span>
                  <span class="site-state-item-name">分类</span>
                
              </div>
            

            
              
              
              <div class="site-state-item site-state-tags">
                
                  <span class="site-state-item-count">2</span>
                  <span class="site-state-item-name">标签</span>
                
              </div>
            

          </nav>

          

          

          
          

          
          

          

        </div>
      </section>

      

      

    </div>
  </aside>


        
      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright">&copy; <span itemprop="copyrightYear">2018</span>
  <span class="with-love">
    <i class="fa fa-user"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">kyssion</span>

  
</div>


  <div class="powered-by">由 <a class="theme-link" target="_blank" href="https://hexo.io">Hexo</a> 强力驱动</div>



  <span class="post-meta-divider">|</span>



  <div class="theme-info">主题 &mdash; <a class="theme-link" target="_blank" href="https://github.com/iissnan/hexo-theme-next">NexT.Mist</a> v5.1.4</div>




        







        
      </div>
    </footer>

    
      <div class="back-to-top">
        <i class="fa fa-arrow-up"></i>
        
      </div>
    

    

  </div>

  

<script type="text/javascript">
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>









  












  
  
    <script type="text/javascript" src="/lib/jquery/index.js?v=2.1.3"></script>
  

  
  
    <script type="text/javascript" src="/lib/fastclick/lib/fastclick.min.js?v=1.0.6"></script>
  

  
  
    <script type="text/javascript" src="/lib/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script>
  

  
  
    <script type="text/javascript" src="/lib/velocity/velocity.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/lib/velocity/velocity.ui.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/lib/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script>
  


  


  <script type="text/javascript" src="/js/src/utils.js?v=5.1.4"></script>

  <script type="text/javascript" src="/js/src/motion.js?v=5.1.4"></script>



  
  

  

  


  <script type="text/javascript" src="/js/src/bootstrap.js?v=5.1.4"></script>



  


  




	





  





  












  





  

  

  

  
  

  

  

  

</body>
</html>
